【问题标题】:Trying to pass two ArrayList that are populated via Firebase in Android试图通过 Android 中通过 Firebase 填充的两个 ArrayList
【发布时间】:2021-06-17 15:24:32
【问题描述】:

我有以下活动需要通过 Firebase 实时数据库填充两个 ArrayList:

pickListener = pickQuery.addValueEventListener(new ValueEventListener() {

    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {

        for (DataSnapshot pickSnapshot : dataSnapshot.getChildren()) {

            Picks pick = new Picks(pickSnapshot);
           
            pickList.add(pick);

        }

    } 

}


mListener = pickQuery.addValueEventListener(new ValueEventListener() {

    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {

        for (DataSnapshot pickSnapshot : dataSnapshot.getChildren()) {

            Game game = new Game(pickSnapshot);
           
            gameList.add(pick);

            if (counter == dataSnapshot.getChildrenCount()) {

                adapter = new GameAdapter(PicksheetActivity.this, gameList, pickList); <---- ISSUE HERE, PASSES NULL ARRAY!? 

                recyclerView.setAdapter(adapter);

            }

        }

    } 

}

所以上面的代码中发生或应该发生的事情是,当pickListgameList 被填充时,它才应该调用适配器来填充视图(项目列表)。

如何实现这一点,有没有办法在 Android 中放置一个完成处理程序,以便在填充一个列表时填充下一个列表,然后调用适配器?

【问题讨论】:

  • 我看不出所提供的监听器之间有什么区别,你有 pickQuery.addValueEventListener 被设置为两个不同的变量,但是同一个监听器

标签: java android firebase firebase-realtime-database android-recyclerview


【解决方案1】:

分配给pickListener 和mListener 的两个回调并行运行。但是 mListener 代码依赖于 pickListener 代码的结果,但是我们不能在异步运行时期望它的结果。通过在方法中放置第二个侦听器,我们可以一个接一个地运行以获得所需的结果。

 pickListener = pickQuery.addValueEventListener(new ValueEventListener() {
    
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
    
            for (DataSnapshot pickSnapshot : dataSnapshot.getChildren()) {
    
                Picks pick = new Picks(pickSnapshot);
               
                pickList.add(pick);
                
                
            }
           getGameList(pickList);
        } 
    
    }
    
    public void getGameList(List<Pick> pickList){
    
    mListener = pickQuery.addValueEventListener(new ValueEventListener() {
    
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
    
            for (DataSnapshot pickSnapshot : dataSnapshot.getChildren()) {
    
                Game game = new Game(pickSnapshot);
               
                gameList.add(pick);
    
                if (counter == dataSnapshot.getChildrenCount()) {
    
                    adapter = new GameAdapter(PicksheetActivity.this, gameList, pickList);  
    
                    recyclerView.setAdapter(adapter);
    
                }
    
            }
    }
    
        } 
    
    }

【讨论】:

  • 我收到一个错误Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setAdapter(androidx.recyclerview.widget.RecyclerView$Adapter)' on a null object reference 我不知道为什么?我唯一能想象的就是因为我把它移到了它自己的功能中。
  • 仔细检查使用 findViewById().@Learn2Code 启动的“recyclerView”
  • 所以看起来 recyclerView 并启动它现在需要在“新”getGameList(List&lt;PIck&gt;pickList) function 中存在/声明。这是出乎意料的,一旦我将 recyclerView 移动到 getGameList 它就起作用了。
  • @androidLearner 虽然这可能会回答问题(我不知道如何回答),但代码块本身通常不是有用的答案,而且更有可能吸引反对票。建议解释您所展示的解决方案的作用,以及该代码为何/如何回答问题。
【解决方案2】:

正如我在您的代码中看到的,您正在执行两个数据库调用来获取两种不同类型的对象。实际发生了什么,两个请求同时发生。由于这两个操作都是异步的,这意味着两者都需要一些时间来完成数据加载,因此您永远不会知道哪个先完成。

为了解决这个问题,您需要等待这两个操作完成。所以最简单的解决方案是使用嵌套侦听器,这意味着您应该将第二个数据库调用移到第一个调用中,反之亦然。一旦第二个数据库调用完成,您就可以调用适配器来填充视图。另请注意使用 addListenerForSingleValueEvent 而不是 addValueEventListener,仅获取一次数据。如果需要实时更新,请注意数据库调用的结果将是一个 DataSnapshot 对象,该对象将包含查询返回的所有数据。所以也要注意处理这种情况。

您拥有的第二个、更新且更实用的选项是使用Tasks#whenAllSuccess() 方法,如以下代码行所示:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query firstQuery = rootRef...
Query secondQuery = rootRef...

Task firstTask = firstQuery.get();
Task secondTask = secondQuery.get();

Task combinedTask = Tasks.whenAllSuccess(firstTask, secondTask).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
    @Override
    public void onSuccess(List<Object> list) {
         //Do what you need to do with your list
    }
});

【讨论】:

  • 对于第一个提议的解决方案,您能否提供代码,我是 Android 新手,在 Swift 中我使用完成处理程序来实现这一点,Android 提供吗?但是,如果您可以请提供有关如何将它们嵌套在 Android 中的代码示例。最后提供的代码示例是针对 Kotlin 的吗?很遗憾我在使用 java?
  • 几乎和 Swift 中的一样。因此,为了实现这一点,您只需将第二个数据库调用移到第一个内部,就在第一个 for 循环结束之后。不,它不是 Kotlin,而是 Java。
  • 是的,我已经获得了上面androidlearner提供的答案
  • 请解释一下您是如何做到的,因为并行查询数据库永远不会提供准确的结果。没有一个听众会知道对方的完成情况。
  • 哦,对不起,你是对的,我所做的是创建一个计数器,它在每个子值上递增,当计数器 == 快照计数时,调用第二个函数来获取游戏数据。 if (counter == dataSnapshot.getChildrenCount()) { getGamesList(pickList); }
猜你喜欢
  • 2021-07-13
  • 2012-07-08
  • 2016-02-15
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 2012-06-15
  • 1970-01-01
  • 2010-12-13
相关资源
最近更新 更多