Firebase android分页

Posted

技术标签:

【中文标题】Firebase android分页【英文标题】:Firebase android pagination 【发布时间】:2016-10-09 05:40:30 【问题描述】:

我正在构建一个应用程序,它将显示存储在 firebase 上的视频。视频列表需要分页,一次获取最近的 20 个视频。

这是我认为可行的代码

  private void getVideos() 

        Query videosQuery = FirebaseUtil.getVideosRef();
        videosQuery.startAt(0);
        videosQuery.endAt(1);

        ChildEventListener videosChildEventListener = new ChildEventListener() 
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) 
                String date = dataSnapshot.getKey();
                String temp = date;
            

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) 

            

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) 

            

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) 

            

            @Override
            public void onCancelled(DatabaseError databaseError) 

                Log.d(tag, "database error");
            
        ;


        ValueEventListener videoValueEventListener = new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 
                String date = dataSnapshot.getKey();
                String temp = date;

               long count =  dataSnapshot.getChildrenCount();
                String value = dataSnapshot.getValue().toString();
                temp = value;
            

            @Override
            public void onCancelled(DatabaseError databaseError) 
                Log.d(tag, "database error");
            
        ;
//        videosQuery.addChildEventListener(videosChildEventListener);
        videosQuery.addValueEventListener(videoValueEventListener);

    

但上面的代码会检索整个视频列表,而不是有限的视频。如何实现分页。

【问题讨论】:

你找到分页的地方了吗? 你有什么分页的吗?我还需要使用 firebase 在我的应用程序中实现分页。 【参考方案1】:

下面是我用于分页的代码,它首先显示最新的节点。

      public void getImages() 
            Query imagesQuery = FirebaseDatabase.getInstance().getReference().child("englishDps").child(mChildName).orderByKey().limitToLast(21);

            ChildEventListener childEventListener = new ChildEventListener() 
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) 
                    Image image = dataSnapshot.getValue(Image.class);
                    image.setNodeKey(dataSnapshot.getKey());

                    mTempImages.add(image);
                    if (mTempImages.size() == 21) 
                        mLastKey = mTempImages.get(0).getNodeKey();
                        Collections.reverse(mTempImages);
                        mTempImages.remove(mTempImages.size() - 1);
                        mImages.addAll(mTempImages);
                        setAdapter();
                    
                

                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) 

                

                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onCancelled(DatabaseError databaseError) 
                    if (isAdded()) 
                        Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
                    
                
            ;

            imagesQuery.addChildEventListener(childEventListener);
        


  @Override
    public void getMoreImages() 
        if (!mGettingMoreImages) 
            mGettingMoreImages = true;
            Query imagesQuery = FirebaseDatabase.getInstance().getReference("englishDps").child(mChildName).orderByKey().endAt(mLastKey).limitToLast(21);

            ChildEventListener childEventListener = new ChildEventListener() 
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) 
                    Image image = dataSnapshot.getValue(Image.class);
                    image.setNodeKey(dataSnapshot.getKey());
                    mMoreImages.add(image);
                    if (mMoreImages.size() == 21) 
                        mLastKey = mMoreImages.get(0).getNodeKey();
                        Collections.reverse(mMoreImages);
                        mMoreImages.remove(mMoreImages.size() - 1);
                        mImages.addAll(mMoreImages);
                        mMoreImages.clear();
                        mGettingMoreImages = false;
                        mImagesAdapter.notifyDataSetChanged();
                        return;
                    

                    if (mLastKey.equalsIgnoreCase(image.getNodeKey())) 
                        Collections.reverse(mMoreImages);
                        mImages.addAll(mMoreImages);
                        mMoreImages.clear();
                        mGettingMoreImages = false;
                        mImagesAdapter.onNoMoreImages();
                        ;
                        mImagesAdapter.notifyDataSetChanged();
                    
                

                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) 

                

                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onCancelled(DatabaseError databaseError) 
                    if (isAdded()) 
                        Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
                    
                
            ;

            imagesQuery.addChildEventListener(childEventListener);
        
    

【讨论】:

你能告诉我 getMoreImages() 是你的覆盖方法吗???我也想使用你使用的分页概念。你的 onLoadMore 功能在哪里?? 片段在我的代码中实现了接口。您可以删除 @override 表示法 您能解释一下.onNoMoreImages(); 是什么吗?谢谢 感谢上面的代码,终于找到我需要的解决方案了!上面的childEvenListener 给了我重复的RecyclerView 项目,因为每次我查询时它们都没有被删除。所以我必须做的不同的是使用addListenerForSingleValueEvent 而不是childEventListener。这样监听器就会立即被移除。再次感谢! 根据 Firebase 文档: 您可以使用 startAt()、endAt() 和 equalTo() 为查询选择任意起点、终点和等价点.这对于对数据进行分页或查找具有特定值的子项非常有用。【参考方案2】:

我有以下方法通过 firebase 实时数据库节点进行分页:

private void getUsers(String nodeId) 
        Query query;

        if (nodeId == null)
            query = FirebaseDatabase.getInstance().getReference()
                    .child(Consts.FIREBASE_DATABASE_LOCATION_USERS)
                    .orderByKey()
                    .limitToFirst(mPostsPerPage);
        else
            query = FirebaseDatabase.getInstance().getReference()
                    .child(Consts.FIREBASE_DATABASE_LOCATION_USERS)
                    .orderByKey()
                    .startAt(nodeId)
                    .limitToFirst(mPostsPerPage);

        query.addListenerForSingleValueEvent(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 
                UserModel user;
                List<UserModel> userModels = new ArrayList<>();
                for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) 
                    userModels.add(userSnapshot.getValue(UserModel.class));
                

                mAdapter.addAll(userModels);
                mIsLoading = false;
            

            @Override
            public void onCancelled(DatabaseError databaseError) 
                mIsLoading = false;
            
        );
    

每次到达分页数据的底部时,我都会调用getUsers(mAdapter.getLastItemId());,然后它会带来下一组记录。

我为此编写了一个包含开源示例应用程序的完整指南,您可以在 https://blog.shajeelafzal.com/2017/12/13/firebase-realtime-database-pagination-guide-using-recyclerview/ 上查看

【讨论】:

【参考方案3】:

您希望使用 limitToFirst/limitToLast 方法来检索有限数量的结果。

videosQuery.orderByKey().limitToFirst(20)

https://www.firebase.com/docs/web/api/query/limittofirst.html

您确实应该考虑更改视频的命名约定以包含前导 0(即 video01、video02...video10、video11),因为上面的代码将完全按照您在上面的方式显示它们(我假设它超出了顺序?)

或者,如果您通过 Java 添加视频,您可以让 firebase 通过 push() 创建唯一 ID。 uniqueid 是以按时间顺序排序的方式生成的,这听起来很适合您获取最新(添加的?)视频的需要。

https://www.firebase.com/docs/web/api/firebase/push.html

【讨论】:

尝试使用 videosQuery.orderByKey().limitToLast(2);使用 ChildEventListener 仍然无法获得分页响应。 这并不是真正的分页答案。它只限制对最后 x 部电影的一次响应。【参考方案4】:
 mPageEndOffset = 0;
 mPageLimit = 10;


 mPageEndOffset += mPageLimit;

 deviceListQuery = mDatabase.child("users")
 .orderByChild("id").limitToFirst(mPageLimit).startAt(mPageEndOffset);

 deviceListQuery.addValueEventListener(YourActivity.this);

【讨论】:

我在让它反向工作时遇到问题,有什么想法吗? ***.com/questions/40231335/… 向数据添加一个具有递减值的字段,例如:unix_timestamp(或倒置时间戳)并在您的选择查询中使用limitToLast()。我们真的不需要分页,因为 firebase 查询执行和返回速度很快。我使用查询在单个查询中获取 1000 条记录到目前为止没有太多延迟 如何附加 unix_timestamp(或倒置时间戳)?目前我正在通过以下方法添加时间戳 'ServerValue.TIMESTAMP' @JayakrishnanPm 好吧,这不会迫使您在视频子实现中拥有一个 id 字段吗?并且 id 需要是一个整数,您必须自己在创建时递增? @JacksOnF1re 如果你想按一个字段(整数字段)排序,然后添加一个时间戳字段,这样你就不需要以编程方式自动递增它。【参考方案5】:

您可以通过使用 Firebase 数据库分页库来实现它,如下代码... 在这段代码中,我将Post 显示为数据模型项,将PostViewHolder 显示为 ViewHolder

        //Initialize RecyclerView
        mRecyclerView = findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);

        LinearLayoutManager mManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mManager);

        //Initialize Database
        mDatabase = FirebaseDatabase.getInstance().getReference().child("posts");

        //Initialize PagedList Configuration
        PagedList.Config config = new PagedList.Config.Builder()
                .setEnablePlaceholders(false)
                .setPrefetchDistance(5)
                .setPageSize(10)
                .build();

        //Initialize FirebasePagingOptions
        DatabasePagingOptions<Post> options = new DatabasePagingOptions.Builder<Post>()
                .setLifecycleOwner(this)
                .setQuery(mDatabase, config, Post.class)
                .build();

        //Initialize Adapter
        mAdapter = new FirebaseRecyclerPagingAdapter<Post, PostViewHolder>(options) 
            @NonNull
            @Override
            public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
                return new PostViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false));
            

            @Override
            protected void onBindViewHolder(@NonNull PostViewHolder holder,
                                            int position,
                                            @NonNull Post model) 
                holder.setItem(model);
            

            @Override
            protected void onLoadingStateChanged(@NonNull LoadingState state) 
                switch (state) 
                    case LOADING_INITIAL:
                    case LOADING_MORE:
                        // Do your loading animation
                        mSwipeRefreshLayout.setRefreshing(true);
                        break;

                    case LOADED:
                        // Stop Animation
                        mSwipeRefreshLayout.setRefreshing(false);
                        break;

                    case FINISHED:
                        //Reached end of Data set
                        mSwipeRefreshLayout.setRefreshing(false);
                        break;

                    case ERROR:
                        retry();
                        break;
                
            

            @Override
            protected void onError(@NonNull DatabaseError databaseError) 
                super.onError(databaseError);
                mSwipeRefreshLayout.setRefreshing(false);
                databaseError.toException().printStackTrace();
            
        ;

        //Set Adapter to RecyclerView
        mRecyclerView.setAdapter(mAdapter);

只需访问以下 URL 以供参考 https://firebaseopensource.com/projects/patilshreyas/firebaserecyclerpagination/app/readme.md/ 在这里,您将找到有助于在 RecyclerView 中实现 Firebase 数据分页的库的实现

希望对你有帮助!

【讨论】:

确保您显示的代码不是来自链接的复制/粘贴或抄袭 这不完全是链接中的复制粘贴。因为在那个链接中,代码是以解释的形式给出的。【参考方案6】:

这就是我从 firebase 数据库实现分页的方式。考虑一个案例,如果我们有 100 条消息。所以我首先从firebase加载最后20条消息,即81到100。然后向上滚动我调用getMoreMessages()函数来加载接下来的20条消息,它们是61到80等等。

public class ChatActivity extends Activity 

        String chat_id = "";
        long mTotalChildren = 0;
        boolean loading = false;
        ChildEventListener childEventListenerMain, childEventListenerPager;
        ChatActivity mContext = ChatActivity.this;
        MessageAdapter messageAdapter;
        @BindView(R.id.pb_messages)
        ProgressBar pb_messages;
        @BindView(R.id.ll_audio)
        LinearLayout llAudio;
        @BindView(R.id.tv_record_time)
        AppCompatTextView tvRecordTime;
        @BindView(R.id.tv_cancel)
        AppCompatTextView tvCancel;
        @BindView(R.id.iv_send)
        AppCompatImageView ivSend;
        @BindView(R.id.iv_record)
        AppCompatImageView ivRecord;
        @BindView(R.id.ab_layout)
        AppBarLayout abLayout;
        @BindView(R.id.messages)
        RecyclerView rvMessages;
        @BindView(R.id.iv_chat_icon)
        SimpleDraweeView ivChatIcon;
        @BindView(R.id.iv_camera)
        AppCompatImageView ivCamera;
        @BindView(R.id.iv_gallery)
        AppCompatImageView ivGallery;
        @BindView(R.id.message_input)
        AppCompatEditText messageInput;
        @BindView(R.id.tv_send)
        AppCompatTextView tvSend;
        @BindView(R.id.toolbar_title)
        AppCompatTextView toolbarTitle;
        @BindView(R.id.toolbar_status)
        AppCompatTextView toolbarStatus;
        @BindView(R.id.ll_send)
        LinearLayout llSend;
        int categoryId, senderId, receiverId, offerId;
        String mLastKey;
        LinearLayoutManager layoutManager;
        private ArrayList<MessageModel> messageArrayList = new ArrayList<>();
        private ArrayList<MessageModel> tempMessageArrayList = new ArrayList<>();

        @Override
        public int getLayoutId() 
            return R.layout.activity_chat;
        

        @Override
        protected void onCreate(Bundle savedInstanceState) 
            super.onCreate(savedInstanceState);

            messageAdapter = new MessageAdapter(mContext, messageArrayList) 

            ;

            layoutManager = new LinearLayoutManager(mContext);

            rvMessages.setLayoutManager(layoutManager);
            rvMessages.setItemAnimator(new DefaultItemAnimator());
            rvMessages.setAdapter(messageAdapter);
            rvMessages.setHasFixedSize(true);

            rvMessages.addOnScrollListener(new RecyclerView.OnScrollListener() 
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) 
                    super.onScrollStateChanged(recyclerView, newState);
                

                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) 
                    super.onScrolled(recyclerView, dx, dy);

                    if (messageArrayList.size() >= 20 &&
                            !loading && layoutManager.findFirstVisibleItemPosition() == 0 && messageArrayList.size() < mTotalChildren) 

                        loading = true;
                        getMoreMessages();
                    
                
            );

            messageAdapter.notifyDataSetChanged();

            //used to scroll up recyclerview when keyboard pops up
            rvMessages.addOnLayoutChangeListener(new View.OnLayoutChangeListener() 
                @Override
                public void onLayoutChange(View view, int left, int top, int right, int bottom,
                                           int oldLeft, int oldTop, int oldRight, int oldBottom) 
                    if (bottom < oldBottom) 
                        rvMessages.postDelayed(new Runnable() 
                            @Override
                            public void run() 
                                rvMessages.scrollToPosition(messageArrayList.size() - 1);
                            
                        , 100);
                    
                
            );

            loading = true;
            getMessages();
        

        public void getMessages() 

            FirebaseDatabase.getInstance().getReference().child(pathtomsgs).addListenerForSingleValueEvent(new ValueEventListener() 
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) 
                    Log.e("childrenCount", String.valueOf(+dataSnapshot.getChildrenCount()));
                    mTotalChildren = dataSnapshot.getChildrenCount();
                

                @Override
                public void onCancelled(DatabaseError databaseError) 

                
            );


            Query messageQuery = FirebaseDatabase.getInstance().getReference().child(pathtomsgs).limitToLast(20);

            childEventListenerMain = new ChildEventListener() 
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) 

                    loading = true;
                    MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
                    if (messageModel != null) 
                        messageModel.chat_id = chat_id;
                        messageModel.message_id = dataSnapshot.getKey();
                        messageArrayList.add(messageModel);
                        messageAdapter.notifyDataSetChanged();
                        mLastKey = messageArrayList.get(0).message_id;
                        rvMessages.scrollToPosition(messageArrayList.size() - 1);
                    
                

                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) 

                

                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onCancelled(DatabaseError databaseError) 
                    Toast.makeText(mContext, "Problem loading more images...", Toast.LENGTH_LONG).show();
                
            ;

            messageQuery.addChildEventListener(childEventListenerMain);

            ValueEventListener messageChildSINGLEValueEventListener = new ValueEventListener() 
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) 
                    pb_messages.setVisibility(View.GONE);
                    System.out.println("We're done loading messages " + dataSnapshot.getChildrenCount() + " items");
                    loading = false;
                

                @Override
                public void onCancelled(DatabaseError databaseError) 

                
            ;

            messageQuery.addListenerForSingleValueEvent(messageChildSINGLEValueEventListener);
        

        public void getMoreMessages() 
            tempMessageArrayList.clear();

            Query messageQuery = FirebaseDatabase.getInstance().getReference().child(pathtomsgs).orderByKey().endAt(mLastKey).limitToLast(20);

            childEventListenerPager = new ChildEventListener() 
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) 
                    loading = true;
                    MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
                    if (messageModel != null) 

                        messageModel.chat_id = chat_id;
                        messageModel.message_id = dataSnapshot.getKey();
                        tempMessageArrayList.add(messageModel);
                    
                

                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) 

                

                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) 

                

                @Override
                public void onCancelled(DatabaseError databaseError) 
                    Toast.makeText(mContext, "Problem loading more images...", Toast.LENGTH_LONG).show();
                
            ;

            messageQuery.addChildEventListener(childEventListenerPager);

            ValueEventListener messageChildSINGLEValueEventListener = new ValueEventListener() 
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) 
                    System.out.println("We're done loading messages " + dataSnapshot.getChildrenCount() + " items");

                    tempMessageArrayList.remove(tempMessageArrayList.size() - 1);

                    messageArrayList.addAll(0, tempMessageArrayList);
                    mLastKey = messageArrayList.get(0).message_id;
                    messageAdapter.notifyDataSetChanged();
                    //rvMessages.scrollToPosition(20);
                    layoutManager.scrollToPositionWithOffset(19, 0);
                    loading = false;
                

                @Override
                public void onCancelled(DatabaseError databaseError) 

                
            ;

            messageQuery.addListenerForSingleValueEvent(messageChildSINGLEValueEventListener);
        


        @Override
        protected void onDestroy() 

            FirebaseDatabase.getInstance().getReference().child(pathtomsgs).removeEventListener(childEventListenerPager);
            FirebaseDatabase.getInstance().getReference().child(pathtomsgs).removeEventListener(childEventListenerMain);

            super.onDestroy();
        
    

【讨论】:

【参考方案7】:

android 分页库可用于对从 firebase 数据库获取的数据进行分页。数据显示在回收器视图中,分页组件获取页面以响应用户滚动事件。

分页数据源调用您的 firebase DAO 对象,传递要显示的页面的查询参数,并使用提供给它的回调将结果传递回分页组件。

这里有一个完整的例子供参考http://www.zoftino.com/firebase-pagination-using-android-paging-library

【讨论】:

【参考方案8】:

接受的答案在小于最大值时不起作用。数据库中的项目(21)。 这是我基于公认答案的解决方案:

0)设置变量

        private String lastMessageKey;
    private int totalItemCount;
    private int lastVisibleItem;
    private boolean isLoadingMoreFollowers = false;
    private boolean hasMoreItems = true;
    private boolean hasShownNoMoreItemsToast = false;
    private boolean initialLoad = true;
    private final int MAX_LOAD_ITEMS = 11;
    private final int VISIBLE_TRESHOLD = 1;

1) 设置监听器:

       private void setMessageListener() 

        if (childEventListener == null) 

            mmessageArrayList.clear();
            final ArrayList<Mmessage> tempMmessages = new ArrayList<>();
            query = mDatabaseInstace.getReference().child(chat1).child(F.CHATS).child(F.MESSAGES).orderByKey().limitToLast(MAX_LOAD_ITEMS-1);
            childEventListener = new ChildEventListener() 
                @Override
                public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) 
                    Log.d(TAG, "onChildAdded: -----------------> " + dataSnapshot);
                    Log.d(TAG, "onChildAdded: -----------------> " + s);

                    tempMmessages.add(dataSnapshot.getValue(Mmessage.class));
                    preloadMessagePics(tempMmessages);
                    if (initialLoad) 
                        lastMessageKey = tempMmessages.get(0).getMessagePushKey();
                        initialLoad = false;
                    
                    mmessageArrayList.add(tempMmessages.size()-1, tempMmessages.get(0));
                    messageAdapter.notifyDataSetChanged();
                    tempMmessages.clear();


                

                @Override
                public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) 
                    Log.d(TAG, "onChildChanged: --------------------------------->");

                

                @Override
                public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) 
                    Log.d(TAG, "onChildRemoved: ---------------------------------->");

                

                @Override
                public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) 
                    Log.d(TAG, "onChildMoved: ------------------------------------>");

                

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) 
                    Log.d(TAG, "onCancelled: ------------------------------------->");

                
            ;
            query.addChildEventListener(childEventListener);
        

    

2) 设置加载更多监听器:

        private void setLoadMoreListener()
        setup.RV_messages.addOnScrollListener(new RecyclerView.OnScrollListener() 
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) 
                super.onScrolled(recyclerView, dx, dy);


                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();



                if (!isLoadingMoreFollowers && totalItemCount <= (lastVisibleItem+VISIBLE_TRESHOLD) && (totalItemCount >= MAX_LOAD_ITEMS-1))

                    if (hasMoreItems) 

                        getMoreMessages();
                        Toast.makeText(homeActivity, "load more items", Toast.LENGTH_SHORT).show();

                    else 
                        if (!hasShownNoMoreItemsToast) 
                            Toast.makeText(homeActivity, "has no more items", Toast.LENGTH_SHORT).show();
                            hasShownNoMoreItemsToast = true;
                        
                    

                

            
        );
    

3) 获得更多物品:

       private void getMoreMessages()

        final ArrayList<Mmessage> tempMmessages = new ArrayList<>();

        isLoadingMoreFollowers = true;
        loadMoreQuery = mDatabaseInstace.getReference().child(chat1).child(F.CHATS).child(F.MESSAGES).orderByKey().endAt(lastMessageKey).limitToLast(MAX_LOAD_ITEMS);
        loadMoreChildEventListener = new ChildEventListener() 
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) 

                tempMmessages.add(dataSnapshot.getValue(Mmessage.class));
                preloadMessagePics(tempMmessages);

                if (tempMmessages.size() == MAX_LOAD_ITEMS)

                    lastMessageKey = tempMmessages.get(0).getMessagePushKey();
                    Collections.reverse(tempMmessages);
                    tempMmessages.remove(0);
                    mmessageArrayList.addAll(tempMmessages);
                    isLoadingMoreFollowers = false;
                    messageAdapter.notifyDataSetChanged();
                    tempMmessages.clear();
                    return;
                


                if (lastMessageKey.equalsIgnoreCase(tempMmessages.get(tempMmessages.size()-1).getMessagePushKey()))

                    Collections.reverse(tempMmessages);
                    tempMmessages.remove(0);
                    mmessageArrayList.addAll(tempMmessages);
                    isLoadingMoreFollowers = false;
                    hasMoreItems = false;
                    messageAdapter.notifyDataSetChanged();
                    tempMmessages.clear();

                

            

            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) 

            

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) 

            

            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) 

            

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) 

            
        ;
        loadMoreQuery.addChildEventListener(loadMoreChildEventListener);

    

玩得开心!

【讨论】:

嘿,你的答案很好,但你能告诉我如何在我的代码中添加它吗?【参考方案9】:

如果你想从 firebase 实时数据库中获取列表并按分页降序,你需要像这样使用 smth:

Query query = myRef.child("stories").orderByChild("takenAt").endAt(1600957136000L).limitToLast(30);

完整代码,两个请求

        List<Story> storyList = new ArrayList<>();
        
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference myRef = database.getReference();
        
        //first request will be look like this
        Query query = myRef.child("stories").orderByChild("takenAt").endAt(1600957136000L).limitToLast(30);
        query.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                if (dataSnapshot.exists()) 
                    for (DataSnapshot snapshot : dataSnapshot.getChildren()) 
                        Story story = snapshot.getValue(Story.class);
                        storyList.add(story);
                    
                
                Collections.reverse(storyList);
            
            @Override
            public void onCancelled(@NonNull DatabaseError error) 
                Log.e("ptg", "onCancelled: ", error.toException());
            
        );
        
        //second request
        long lastTakenAtInTheStoryList = storyList.get(storyList.size()-1).getTakenAt();
        Query query2 = myRef.child("stories").orderByChild("takenAt").endAt(lastTakenAtInTheStoryList).limitToLast(30);
        query2.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                if (dataSnapshot.exists()) 
                    for (DataSnapshot snapshot : dataSnapshot.getChildren()) 
                        Story story = snapshot.getValue(Story.class);
                        storyList.add(story);
                    
                
                Collections.reverse(storyList);
            
            @Override
            public void onCancelled(@NonNull DatabaseError error) 
                Log.e("ptg", "onCancelled: ", error.toException());
            
        );

【讨论】:

【参考方案10】:

过去(但不再)a question 关于对 Firestore 上的查询实施分页被标记为此问题的副本,我将在此处为 FireStore 回答。

在 android Firestore 上对查询进行分页

Query query = db.collection("cities")
        .orderBy("population")
        .limit(25);

Query next = query;

 private void loadCities() 

     query = next;
     query.get()
        .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() 
            @Override
            public void onSuccess(QuerySnapshot documentSnapshots) 

                // Get the last visible document
                DocumentSnapshot lastVisible = 
                documentSnapshots.getDocuments()
                        .get(documentSnapshots.size() -1);

                // Construct a new query starting at this document,
                // get the next 25 cities.
                next = db.collection("cities")
                        .orderBy("population")
                        .startAfter(lastVisible)
                        .limit(25);

            
        );         
 

现在,只要您需要加载更多城市,只需调用 loadCities() 方法即可。

【讨论】:

这个答案对于 firestore 数据库可能是正确的,但问题是在 firebase 数据库上。 请回答 Firebase 实时数据库

以上是关于Firebase android分页的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Firebase 分析跟踪 android 片段

在android中获取firebase用户ID

Firebase android分页

Uncaught FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - 在 vue.js 中调用 Fireba

Stripe 和 Firebase:FirebaseError:collection() 的第一个参数应为 CollectionReference、DocumentReference 或 Fireba

将数据从firebase函数返回到android [重复]