【问题标题】:Firebase LimitToLast crash when trying to load new data尝试加载新数据时 Firebase LimitToLast 崩溃
【发布时间】:2018-08-29 11:56:25
【问题描述】:

在我的 20 个用户发布到我的 ListView 后,我试图加载更多元素(此功能运行良好),但是当我滚动到 ListView 的底部时,我想加载另外 20 个用户,但它崩溃了。

这是我到目前为止所做的

FilterData.class

private String oldestUserID;

private void fetchData(DataSnapshot dataSnapshot) {

    mList.clear();

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

        oldestUserID = dataSnapshot.getKey();
        userPojo = snapshot.getValue(UserPojo.class);
        String email = userPojo.getEmail();
        mList.add(email);
    }
    fetchSuccessListener.onListFetched(true);
}

public void refillListView(ListView listView) {

    listView.setOnScrollListener(new AbsListView.OnScrollListener() {

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            currentScrollState = scrollState;
            isScrollCompleted();

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                             int visibleItemCount, int totalItemCount) {
            currentFirstVisibleItem = firstVisibleItem;
            currentVisibleItemCount = visibleItemCount;
            totalItem = totalItemCount;

        }

        private void isScrollCompleted() {
            if (totalItem - currentFirstVisibleItem == currentVisibleItemCount
                    && currentScrollState == SCROLL_STATE_IDLE) {

                mDatabase.orderByKey().startAt(oldestUserID).limitToFirst(20).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        fetchData(dataSnapshot);
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });
            }


        }


    });
}

这就是它的工作方式,我使用一个界面来检测我的数据何时完成获取并通知我的适配器填充 ListView,这对我的前 20 个用户来说工作正常,但是当我滚动到最后时,我想要添加新用户的列表(另外 20 个),但我得到了这个崩溃日志

无法在先前设置限制的查询中调用 limitToLast!

现在,这是我调用方法以获取数据的方式

MainActivity.class

检索数据时填充列表视图的接口(工作正常)

@Override
public void onListFetched(boolean fetched) {
    if(fetched){

        mUserListView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
    }
}

这只是为了知道用户何时滚动并需要再加载 20 个用户

filterData.refillListView(mUserListView);

我在上面尝试做的是获取数据库中的最后一个用户 ID,以便在最后一个查询后开始查询 20 个新用户,这样我可以再加载 20 个。

这是我用来获取前 20 个用户的查询

 mRootDatabase = FirebaseDatabase.getInstance().getReference().child("Usuarios");
        query = mRootDatabase.limitToFirst(20);

Firebase 数据库结构如下所示

编辑:Logcat 错误指向这一行

mDatabase.orderByKey().startAt(oldestUserID).limitToFirst(20).....

感谢您的帮助!

编辑:sn-p

public void refillListView() {
mQueryDatabase.orderByKey().startAt(oldestUserID).limitToFirst(20).addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot dataSnapshot) {
                            fetchData(dataSnapshot);
                        }

                        @Override
                        public void onCancelled(DatabaseError databaseError) {

                        }
                    });
}

private Query mQueryDatabase; 与我的构造函数一起传递的位置

public FilterData(Query mQueryDatabase, Context context) {
        this.mQueryDatabase = mQueryDatabase;
        this.userPojo = new UserPojo();
        this.mContext = context;
    }

像这样填充

  Query query = mRootDatabase.limitToFirst(20);
       FilterData filterData  = new FilterData(query,this);

oldestUserID 取自 fetchData(dataSnapshot);

fetchData 在哪里

private void fetchData(DataSnapshot dataSnapshot) {

        mList.clear();

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

            oldestUserID = snapshot.getKey();
            userPojo = snapshot.getValue(UserPojo.class);
            String email = userPojo.getEmail();
            mList.add(email);
        }
        fetchSuccessListener.onListFetched(true);
    }

【问题讨论】:

  • 当您在单个查询中多次调用limitToFirst() 和/或limitToLast() 时会引发该错误。我从来没有见过它没有这个原因被抛出,所以这是我的第一个怀疑。您能否在不滚动的情况下重现问题,以便我可以在不需要任何 UI 的单个 sn-p 中看到问题?
  • 顺便说一句:在 Firebase 实时数据库上正确实现无限滚动的概念非常棒。由于 Firebase 查询不是基于偏移量的,因此大多数不熟悉 Firebase 的开发人员都对此感到很困惑。 :-)
  • 嘿,非常感谢坦率,我现在就去做,让你知道
  • 这就是我得到的坦率你必须结合 orderByKey() 使用 startAt(String value)、endAt(String value) 或 equalTo(String value)。不支持其他类型的值或使用带 2 个参数的版本
  • 如果您可以在一个我可以复制/粘贴的 sn-p 中重现,我可以看看。现在,我错过了 mDatabase 的初始化方式。通过将所有内容放在一个独立的代码中,您可以让其他人轻松地在我们的屏幕上遇到相同的问题,从而更容易看到发生了什么。这样一个所谓的MCVE(请阅读链接,它非常有用)确实是在代码相关问题上获得帮助的最佳方式。

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


【解决方案1】:

据我所知,您最初是这样做的:

Query query = mRootDatabase.limitToFirst(20);
FilterData filterData  = new FilterData(query,this);

然后FilterData 会这样做:

public FilterData(Query mQueryDatabase, Context context) {
    this.mQueryDatabase = mQueryDatabase;
    this.userPojo = new UserPojo();
    this.mContext = context;
}

然后:

mQueryDatabase.orderByKey().startAt(oldestUserID).limitToFirst(20).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        fetchData(dataSnapshot);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});

在这一点上,如果我们将这些东西链接在一起,你有:

mRootDatabase
  .limitToFirst(20)
  .orderByKey()
  .startAt(oldestUserID)
  .limitToFirst(20)
  .addListenerForSingleValueEvent(
    ...

因为你有两次limitToFirst(20),它解释了为什么你会收到一条错误消息。

我的直觉是你想将查询的根引用传递给FilterData,所以:

FilterData filterData  = new FilterData(mRootDatabase,this);

或者,您可以在FilterData 之外构建基本查询(查询的所有不变部分):

Query query = mRootDatabase.orderByKey().limitToFirst(20);

然后在FilterData 中只添加变量部分(startAt() 子句):

mQueryDatabase.startAt(oldestUserID).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        fetchData(dataSnapshot);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});

【讨论】:

  • 很高兴听到托德。请注意,这正是我们要求single, self-contained MCVE 的原因,这涉及设置一个重现问题的小型新项目/方法。开发人员通常在构建 MCVE 时自己发现问题。
【解决方案2】:

在这里,我完成了 Firebase-Chat-Pagination。检查一下。它可能对你有帮助。

private void loadDataFirst() {
    mUserRefValueEventListener = mConversationRef.child(mLocation)
            .limitToLast(TOTAL_ITEM_EACH_LOAD)
            .orderByKey()
            .addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    // It should be null when new meesage sent by own
                    mLastDataSnapshot = null;
                    if (dataSnapshot.exists()) {
                        mChatList.clear();
                        for (DataSnapshot readDataSnapshot : dataSnapshot.getChildren()) {
                            ChatResponse chatModel = readDataSnapshot.getValue(ChatResponse.class);
                            if (chatModel != null) {
                                mChatList.add(chatModel);
                            }
                            // We need First DataSnapshot for pagination
                            if (mLastDataSnapshot == null) {
                                mLastDataSnapshot = readDataSnapshot;
                            }

                        }
                        mView.onFetchMessagesSuccess(mChatList);
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });

}

 public void loadMoreDataPagination() {

    if (mLastDataSnapshot != null && (mTotalCount == 0 || mView.getChatMessageCount() < mTotalCount)) {
        mUserRefValueEventListener = mConversationRef.child(mLocation)
                .orderByKey()
                .endAt(mLastDataSnapshot.getKey())
                .limitToLast(TOTAL_ITEM_EACH_LOAD)
                .addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {


                        if (dataSnapshot.exists()) {
                            mChatList.clear();
                            for (DataSnapshot readDataSnapshot : dataSnapshot.getChildren()) {
                                ChatResponse chatModel = readDataSnapshot.getValue(ChatResponse.class);
                                if (chatModel != null) {
                                    mChatList.add(chatModel);
                                }
                                // We need Last DataSnapshot for pagination while load more
                                if (mChatList.size() == 1) {
                                    mLastDataSnapshot = readDataSnapshot;
                                }
                            }
                            // One item duplicates from last list so need to Remove it
                            mChatList.remove(mChatList.size() - 1);
                            mView.onFetchLoadMoreSuccess(mChatList, mTotalCount);

                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                        mView.hideLoading();
                    }
                });
    }
}

【讨论】:

    猜你喜欢
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 2019-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 1970-01-01
    相关资源
    最近更新 更多