在 Firebase Listener 中设置 Singleton 属性值

2024-06-24

我目前正在测试 Firebase 以及我计划在整个应用程序的生命周期中用于访问的单例模型。我现在被一些看似微不足道的事情所困扰,但我一生都无法弄清楚。我有一个我使用的模型的示例:Bookmarks in firebase。

public class BookSingleton {



private static BookSingleton model;

private ArrayList<BookMark> bookmarks = new ArrayList<BookMark>();


public static BookSingleton getModel()
{
    if (model == null)
    {
        throw new IllegalStateException("The model has not been initialised yet.");
    }

    return model;
}


public ArrayList<Bookmark> theBookmarkList()
{
    return this.bookmarks;
}


public void setBookmarks(ArrayList<Bookmark> bookmarks){
    this.bookmarks = bookmarks;
}


public void loadModelWithDataFromFirebase(){
    Firebase db = new Firebase(//url);
    Firebase bookmarksRef = fb.child(//access correct child);


    final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>();
    bookmarksRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
                    //getting all properties from firebase...
                    Bookmark bookmark = new Bookmark(//properties here);
                    loadedBookmarks.add(bookmark);



                }
            }
            //bookmarks still exist here at this point
            setBookmarks(loadedBookmarks);

        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {

        }
    });
    //by now loadedBookmarks is empty
    //this is probably the issue?
    //even without this line bookmarks is still not set in mainactivity
    setBookmarks(loadedBookmarks);
}

现在,当我使用 Singleton 集的实例启动 mainActivity 时,我收到一个 null 错误,因为显然我编写的从 firebase 加载模型数据的函数没有设置任何内容。

像这样的事情:MainActivity

public class MainActivity extends AppCompatActivity {

private BookSingleton theModel;



@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    // Load the model
    theModel = BookSingleton.getModel(this);
      //manually setting this works 
      //        ArrayList<Book> bookSamples = new ArrayList<Book>;
      //        bookSamples.add(aBookSample);

    theModel.loadModelWithSampleData(bookSamples);
    //should have set the singleton model property Bookmarks to the results from firebase

    theModel.loadModelWithDataFromFirebase();
    //returns 0
    Log.d(TAG, "" + theModel.theBookmarkList().size());


    setContentView(R.layout.activity_main);

    //......rest of code

我怎样才能做到这一点?


Firebase加载并同步数据异步地。所以你的loadModelWithDataFromFirebase()不等待加载完成,它只是starts从数据库加载数据。到时候你的loadModelWithDataFromFirebase()函数返回,加载尚未完成。

您可以使用一些适当的日志语句轻松地自行测试:

public void loadModelWithDataFromFirebase(){
    Firebase db = new Firebase(//url);
    Firebase bookmarksRef = fb.child(//access correct child);

    Log.v("Async101", "Start loading bookmarks");
    final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>();
    bookmarksRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Log.v("Async101", "Done loading bookmarks");
            //getting all properties from firebase...
            Bookmark bookmark = new Bookmark(//properties here);
            loadedBookmarks.add(bookmark);
        }

        @Override
        public void onCancelled(FirebaseError error) { throw error.toException(); }
    });
    Log.v("Async101", "Returning loaded bookmarks");
    setBookmarks(loadedBookmarks);
}

与您可能期望的相反,日志语句的顺序将是:

Start loading bookmarks
Returning loaded bookmarks
Done loading bookmarks

您有两种选择来处理此加载的异步性质:

  1. 消除异步错误(通常伴随着诸如此类的嘀咕短语:“这是一个错误,这些人不知道他们在做什么”)

  2. 拥抱异步野兽(通常伴随着相当长的时间的咒骂,但一段时间后就会和平和表现更好的应用程序)

服用蓝色药丸 - 使异步调用同步运行

如果您想选择第一个选项,一个放置良好的同步原语就可以解决问题:

public void loadModelWithDataFromFirebase() throws InterruptedException {
    Firebase db = new Firebase(//url);
    Firebase bookmarksRef = fb.child(//access correct child);

    Semaphore semaphore = new Semaphore(0);

    final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>();
    bookmarksRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Bookmark bookmark = new Bookmark(//properties here);
            loadedBookmarks.add(bookmark);
            semaphore.release();
        }

        @Override
        public void onCancelled(FirebaseError error) { throw error.toException(); }
    });
    semaphore.acquire();
    setBookmarks(loadedBookmarks);
}

更新(20160303):当我刚刚在 Android 上测试这个时,它阻止了我的应用程序。它可以在常规 JVM 上正常运行,但 Android 在线程处理方面更加挑剔。请随意尝试并使其发挥作用......或者

服用红色药丸 - 处理 Firebase 中数据同步的异步性质

如果您选择采用异步编程,则应该重新考虑应用程序的逻辑。

您当前拥有“首先加载书签。然后加载示例数据。然后加载更多数据。”

使用异步加载模型,您应该这样想:“每当加载书签时,我想要加载示例数据。每当加载示例数据时,我想要加载更多数据。”

以这种方式思考的好处是,当数据可能不断变化并因此多次同步时,它也适用:“每当书签发生变化时,我也想加载示例数据。每当示例数据发生变化时,我什至想加载更多的。”

在代码中,这会导致嵌套调用或事件链:

public void synchronizeBookmarks(){
    Firebase db = new Firebase(//url);
    Firebase bookmarksRef = fb.child(//access correct child);

    final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>();
    bookmarksRef.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Bookmark bookmark = new Bookmark(//properties here);
            loadedBookmarks.add(bookmark);
            setBookmarks(loadedBookmarks);
            loadSampleData();
        }

        @Override
        public void onCancelled(FirebaseError error) { throw error.toException(); }
    });
}

在上面的代码中,我们不只是等待单个值事件,而是处理所有事件。这意味着每当书签发生更改时,onDataChange被执行,我们(重新)加载示例数据(或任何其他适合您的应用程序需求的操作)。

为了使代码更可重用,您可能需要定义自己的回调接口,而不是调用中的精确代码onDataChange。看一下这个答案 https://stackoverflow.com/a/50435519就是一个很好的例子。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Firebase Listener 中设置 Singleton 属性值 的相关文章

  • 从设备获取日期并将其转换为 GMT+4

    我正在尝试查找 Android 手机的时区 因为我想获取日期对象 但我想要 GMT 4 格式 我看到的所有其他答案都会转换来自 API 请求的时间 其时区已知 我怎样才能做到这一点 其他方法可能是将服务器传来的 GMT 4 时间转换为我设备
  • 我应该在远程工作站的哪里放置 CSV 配置文件以进行分布式 JMeter 测试?

    我想做JMeter分布式测试 手册上说首先我应该开始jmeter server在远程节点上 然后我应该更新jmeter config并运行jmeter在主节点上 我做了所有这些步骤 我的测试计划包括使用 CSV 配置文件 如果我只从 1 个
  • Run As JUnit 未出现在 Eclipse 中 - 使用 JUnit4

    我正在尝试为我的 Web 应用程序编写 JUnit4 测试 它们之前一直工作正常 但是 现在当我尝试通过右键单击类文件 gt Run As gt JUnit Test 来运行测试时 我看不到该选项 我认为这可能是因为一位同事意外提交了一些
  • 获取 Spring Boot 中当前活动数据源的引用

    我想通过实现数据库数据初始化DataSourceInitializer 我将这些方法放在我的 Spring Boot 主方法下面 但似乎它根本没有被执行 我尝试故意删除字符只是为了触发一个错误来确认执行 什么也没有发生 Configurat
  • Apache HTTPClient SSLPeerUnverifiedException

    使用 Apache HttpClient 4 2 1 使用从基于表单的登录示例复制的代码 http hc apache org httpcomponents client ga examples html http hc apache or
  • 画廊新媒体如何播放?

    我试图收到有关添加到手机图库的新图片或视频的通知 我需要获取新媒体的 URI 目的是让我可以自动备份它 因此 我需要一个在后台设置的寄存器来连续侦听或检查添加到图库的新媒体 并捕获 Uri 这过去是通过广播接收器完成的 例如
  • NoSuchMethodError:org.springframework.data.repository.config.RepositoryConfigurationSource.getAttribute

    我正在尝试在 spring boot 应用程序中使用 spring data redis 来使用 redis 我正在创造JedisConnectionFactory如下 RedisStandaloneConfiguration config
  • 将 Tango 3D 点投影到屏幕 Google Project Tango

    Project Tango 提供了点云 如何获取点云中 3D 点的像素位置 以米为单位 我尝试使用投影矩阵 但得到的值非常小 0 5 1 3 等 而不是 1234 324 以像素为单位 我包含我尝试过的代码 Get the current
  • Selenium - WebDriver.findElement() 和 WebElement.findElement() 之间的区别

    我正在使用WebElement findElement By cssSelector click 在页面上查找某个元素 但它返回了 Unable to locate element 但是当我使用WebDriver findElement B
  • Android 中的 SeekBar setMin 至少需要 api 26?

    我想在我的 Android 应用程序中使用 SeekBar 我的minsdk版本必须是23 编译器说SeekBar的setMin至少需要API级别26 我是否需要一些特殊的支持库来实现简单的 SeekBar setMin 我在 Linux
  • Java - 动态创建子类

    我想以编程方式创建一个子类 我想我的选择很少 Javassist CGLib BCEL 或 ASM 用例是一个应用程序的内部是面向类的 而扩展是基于类的 因此 我不能将单个类作为由外部化脚本驱动的多个扩展的基础 现在 我该怎么做呢 我找到了
  • 在 libgdx 中截取屏幕截图

    我有一个应用程序 我想在其中截取游戏屏幕的屏幕截图并将其保存为图像并上传到 Facebook 我正在使用 Libgdx 我的重点是 android 谁能帮助我如何以编程方式截取游戏屏幕并将其另存为图像 现在相当容易 Libgdx提供了一个例
  • Android Google plus 注销按钮看起来与 Google 教程文档中的登录按钮不同

    我正在按照 Google 开发人员网站中提到的步骤在我的应用程序中实现登录和注销 如前所述 添加登录和退出按钮的代码是
  • 是否可以通过 MediaRecorder 或其他类获取当前样本幅度

    我有一个媒体录音机 想要从麦克风录制媒体并获取 它是幅度样本 我想尝试立即获得正确的当前幅度 当调用一些API时 但 MediaRecorde 中只有一个 API 用于获取幅度 getMaxAmplitude 用于获取最大绝对幅度 自上次调
  • allure2 侦听器在控制台中输出步骤

    我正在使用 Allure2 和 TestNG 我想编写自己的侦听器 在控制台输出中打印 Steps 我在 allure 中看到了 StepLifecycleListener 接口 但我无法在 TestNg 中实现此侦听器 有什么指点吗 Ov
  • JPA2+Hibernate 3.6.0 中的 JTA 还是 LOCAL 事务?

    我们正在重新思考我们的技术堆栈 以下是我们的选择 由于应用程序的复杂性等 我们不能没有 Spring 和 Hibernate 我们还从 J2EE 1 4 迁移到 Java EE 5 技术栈 Java EE 5 JPA 2 0 我知道Java
  • GridLayout 中的 JLabel

    如何添加JLabel出于GridLayout 我有一个 8x8 网格布局 Container content getContentPane content setLayout new GridLayout 8 8 2 2 for int f
  • 解决SecurityException:权限拒绝:启动意图。我需要什么许可?

    我想从应用程序打开游戏商店 在三星手机上还好 但在一加手机上却失败了 我不知道在哪里alibaba来自 真奇怪 异常 java lang SecurityException 权限拒绝 启动意图 act android intent acti
  • DDMS 未显示来自设备的线程

    我想使用以下命令检查我的 Android 应用程序中是否存在内存泄漏DDMS特色于Eclipse 当我启动模拟设备时 线程会正确显示模拟设备 从 8600 及更高版本开始 然而 当我将 Droid 连接到 PC 时 该设备在 DDMS 中显
  • 如何处理JFreeChart中的SpiderWebPlot?

    发现 JFreeChart 我在使用时遇到了问题蜘蛛网情节 http www jfree org jfreechart api javadoc org jfree chart plot SpiderWebPlot html 这就是我今天所拥

随机推荐

  • ViewHolder 选择问题

    我正在一个应用程序中工作 在该应用程序中我处理ListView这是复合的ViewHolder 在这个ViewHolder 我有一个CheckBox 这是我的代码 private class SettingsArrayAdapter exte
  • IOS:关闭两个viewController

    我有三个viewController 第一 第二和第三 从第二个到打开第三个我用 Third third Third alloc initWithNibName Third bundle nil self presentModalViewC
  • 将 FirebaseUI 与 AngularFire2 结合使用

    我还没有找到任何样本 是否可以使用Firebase用户界面 https github com firebase firebaseui web使用 AngularFire2 AFAIK UI 不是 AngularFire2 的一部分 是的 A
  • 为什么 ActionChains(driver).move_to_element(elem).click().perform() 两次

    我尝试通过爬取包含关键词的微信公众号http weixin sogou com http weixin sogou com 但我发现我必须使用twice ActionChains driver move to element nextpag
  • ASP.Net MVC 在哪里从实体转换为视图模型?

    标题几乎解释了一切 这是我在我们的项目中尝试做的最后一件事 我们的结构是一个服务库 其中包含这样的功能
  • Facebook 电子邮件始终通过 FQL 和 RestFB 返回 null

    我正在尝试将朋友页面转换为粉丝页面 大多数企业都错误地创建了朋友页面 并尝试向朋友列表中的每个人发送有关此举的电子邮件 我试过了 FQL 从用户中选择电子邮件 其中 uid xxxx 创建群组 不适合 5000 个朋友页面 Restfb C
  • jQuery Mobile 延迟加载列表项

    您如何知道您位于 jQuery Mobile 列表的底部 当到达列表末尾时我需要延迟加载更多结果 有一个使用的工作示例scrollstart and scrollstop这里发生的事件 应该会让您朝着正确的方向前进 http jsfiddl
  • Laravel Forge + DigitalOcean - 添加仅对目录具有受限访问权限的 SFTP 用户

    我在 DigitalOcean Droplet 中使用 Laravel Forge 我需要向我的一个客户端授予对服务器上特定目录的 SFTP 访问权限 他只需要对该目录的读 写访问权限 而我的设置遇到问题 我已按照以下步骤操作https b
  • 什么是调度抖动?

    我一直在阅读一篇关于使用Linux操作系统的实时系统的论文 并且重复使用术语 调度抖动 而没有定义 什么是调度抖动 这是什么意思 抖动是给定任务的后续时间段之间的差异 在实时操作系统中 将抖动降低到应用程序可接受的水平非常重要 这是抖动的图
  • 计算某些值的累积和

    假设您有一个像这样的数据框 df lt data frame Nums c 1 2 3 4 5 6 7 8 9 10 Cum sums NA gt df Nums Cum sums 1 1 NA 2 2 NA 3 3 NA 4 4 NA 5
  • 如何使用 javascript 创建一个在记事本中正确显示的新行?

    我有一个脚本 可以将表格单元格从浏览器复制到用户的剪贴板中 我循环遍历每个单元格 当需要新行时我使用 text n 如果我将文本粘贴到 Excel 中 它会正确格式化并填充正确的行 但是如果我粘贴到记事本中 它会显示一个符号而不是创建新行
  • 如何使用 caliburn.micro 绑定到命令属性?

    我的行为公开了多个命令属性 通常 我使用 MVVM Light 只在视图模型中使用路由命令并绑定到这些命令 然而 这个项目正在使用 Caliburn Micro 所以我尝试以 Caliburn Micro 的方式进行操作 我可以在 Mess
  • 301 重定向 .htaccess

    如何进行301重定向 例如 子目录 Blog to blog 与 htaccess Redirect 301 Blog blog 或者使用类似的东西http www htaccessredirect net index php http w
  • 通过相邻行的差异过滤 pandas 数据框

    我有一个按日期时间索引的数据框 我想根据行的索引与前一行的索引之间的差异来过滤行 因此 如果我的标准是 删除比前一行晚一小时以上的所有行 则应删除下面示例中的第二行 2005 07 15 17 00 00 2005 07 17 18 00
  • 如何在启用保管库锁定的情况下将对象从 Amazon S3 移动到 Glacier?

    我正在寻找一种在启用 Vault Lock 的情况下将 Amazon S3 对象移动到 Glacier 的解决方案 如此处所述https aws amazon com blogs aws glacier vault lock https a
  • 为什么 ++i++ 在 C 中给出“L-value required error”? [复制]

    这个问题在这里已经有答案了 在下面的代码中 main int i 5 printf d i 该程序给出错误 L Value required 有人可以告诉我吗 为什么编译出错 由于后缀运算符的优先级高于前缀运算符 因此表达式 i 相当于 i
  • 选择另一个下拉列表时填充下拉列表[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Camel-拆分 List 并处理每个 java 对象 - XML Config

    我无法拆分列表中的 Java 对象 如何将 Body 标记化 转换为单个 java 对象
  • 如何在放大高图表时启用 y 轴平移?

    我想在放大图表时沿 Y 轴移动 现在我可以在缩放时在 X 轴上移动 下面是平移的代码 chart renderTo container1 type column zoomType xy panning true panKey shift 任
  • 在 Firebase Listener 中设置 Singleton 属性值

    我目前正在测试 Firebase 以及我计划在整个应用程序的生命周期中用于访问的单例模型 我现在被一些看似微不足道的事情所困扰 但我一生都无法弄清楚 我有一个我使用的模型的示例 Bookmarks in firebase public cl