简体   繁体   English

当用户滚动到RecyclerView的底部时,使用ScrollListener从Firebase Realtime DB中提取数据

[英]Issue using ScrollListener to pull data from Firebase Realtime DB when user scrolls to the bottom of a RecyclerView

I have an application that pulls object data from a Firebase Realtime DB, adds it to an ArrayList, which is then added to a RecyclerView. 我有一个应用程序从Firebase实时数据库中提取对象数据,将其添加到ArrayList,然后将其添加到RecyclerView。 I utilize an onScrollListener on my RecyclerView so that when a user scrolls to the bottom of the RecyclerView, a function is called to pull more data from Firebase, add it to the ArrayList and notify the RecyclerViewAdapter of the Data set change. 我在RecyclerView上使用了onScrollListener,这样当用户滚动到RecyclerView的底部时,会调用一个函数从Firebase中提取更多数据,将其添加到ArrayList并通知RecyclerViewAdapter数据集更改。

When I run my application, it presents the initial pull of data in my RecyclerView, then immediately begins calling the function to fetch more data from my DB continuously until there is no more data left to pull and my RecyclerView is updated with this data; 当我运行我的应用程序时,它会在我的RecyclerView中显示最初的数据提取,然后立即开始调用该函数以持续从我的数据库中获取更多数据,直到没有剩余的数据可以拉动并且我的RecyclerView使用这些数据进行更新; this occurs regardless of whether I scroll(in any direction/of any magnitude) or not. 无论我是否滚动(在任何方向/任何幅度),都会发生这种情况。

Ideally, I would want the application to only pull data if the user scrolled to the bottom of the RecyclerView, and to do so one pull at a time. 理想情况下,如果用户滚动到RecyclerView的底部,我希望应用程序只提取数据,并且一次拉一次。 I'm having a very hard time debugging this issue as the logic seems to be correct; 由于逻辑似乎是正确的,我很难调试这个问题; any help would be immensely appreciated. 任何帮助都会非常感激。

Relevant global variables 相关的全局变量

RecyclerView rvVertical;
RecyclerViewAdapter rvaVertical;
long mTotalChildren = 0;
int mLastKey = 0;

ChildEventListener childEventListenerMain, childEventListenerPager;
boolean Loading = false;

private ArrayList<BlogObject> blogArray = new ArrayList<>();
private ArrayList<BlogObject> tempList = new ArrayList<>();

View loaded 查看已加载

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    final View view = inflater.inflate(R.layout.socialmediatab, container, false);

    rvVertical = (RecyclerView) view.findViewById(R.id.bloglistRecyclerView);
    Loading = true;
    Log.d(TAG, "onCreateView - Loading = " + Loading);
    firstEventListener();
    regAdapterVertical();

    addOnScrollListener();
    return view;
}

First function that gets called. 第一个被调用的函数。 initializes the first pull of data from Firebase 从Firebase初始化第一批数据

private void firstEventListener() {

    FirebaseDatabase.getInstance().getReference().child("blogs").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            mTotalChildren = dataSnapshot.getChildrenCount();
        }
        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) { }
    });

    final Query BlogQuery = FirebaseDatabase.getInstance().getReference().child("blogs").orderByChild("createdAt").limitToLast(3);

    childEventListenerMain = new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot ds, String s) {
            Loading = true;
            Log.d(TAG, "First get blogs instance - Loading = " + Loading);
            BlogObject addblog = ds.getValue(BlogObject.class);

            if (addblog != null) {
                BlogObject addBlog = new BlogObject(ds.getValue(BlogObject.class).getImage(), ds.getValue(BlogObject.class).getTitle(), ds.getValue(BlogObject.class).getTimeStamp(), ds.getValue(BlogObject.class).getCreatedAt());
                blogArray.add(addBlog);
                rvaVertical.notifyDataSetChanged();
                mLastKey = blogArray.get(0).getCreatedAt();
                rvVertical.scrollToPosition(blogArray.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) { }
    };

    BlogQuery.addChildEventListener(childEventListenerMain);
    ValueEventListener BlogChildSingleListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            Loading = false;
        }
        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) { }
    };

    BlogQuery.addListenerForSingleValueEvent(BlogChildSingleListener);
}

Adding the Scroll Listener to my Recycler View. 将Scroll Listener添加到Recycler View。 Ideally, it is only supposed to fetch more data from Firebase if and only if the user scrolls to the bottom of the RecyclerView 理想情况下,当且仅当用户滚动到RecyclerView的底部时,它才应该从Firebase获取更多数据

private void addOnScrollListener() {
    rvVertical.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }

        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            Log.d(TAG, "Just Entered onScrolled and Loading = " + Loading);
            super.onScrolled(recyclerView, dx, dy);

            if(!rvVertical.canScrollVertically(1)) {
                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                if (blogArray.size() >= 3 && !Loading && linearLayoutManager.findLastCompletelyVisibleItemPosition() == blogArray.size() - 1 && blogArray.size() < mTotalChildren) {
                    Loading = true;
                    getMoreBlogs();
                    Log.d(TAG, "Right After getMoreBlogs gets called. Loading = " + Loading);
                }
            }
        }
    });
}

Initializing Adapter with first pull of data 使用第一次数据初始化适配器

private void regAdapterVertical() {
    LinearSnapHelper linearSnapHelper = new SnapHelperOneByOne();
    linearSnapHelper.attachToRecyclerView(rvVertical);
    rvaVertical = new RecyclerViewAdapter(blogArray);
    rvVertical.setAdapter(rvaVertical);
    rvVertical.setLayoutManager((RecyclerView.LayoutManager) new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
}

This is my function to pull more data from Firebase. 这是我从Firebase获取更多数据的功能。 It gets called in my Scroll Listener 它在我的Scroll Listener中被调用

public void getMoreBlogs() {
    tempList.clear();

    Query getMoreQuery = FirebaseDatabase.getInstance().getReference().child("blogs").orderByChild("createdAt").endAt(mLastKey).limitToLast(3);
    childEventListenerPager = new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot ds, String s) {
            Loading = true;
            BlogObject blogObject = ds.getValue(BlogObject.class);
            if (blogObject != null) {
                BlogObject addBlog = new BlogObject(ds.getValue(BlogObject.class).getImage(), ds.getValue(BlogObject.class).getTitle(), ds.getValue(BlogObject.class).getTimeStamp(), ds.getValue(BlogObject.class).getCreatedAt());
                tempList.add(addBlog);
            }
        }

        @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) { }
    };

    getMoreQuery.addChildEventListener(childEventListenerPager);

    ValueEventListener addtoAdapter = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            tempList.remove(tempList.size() - 1);
            blogArray.addAll(0, tempList);
            mLastKey = blogArray.get(0).getCreatedAt();
            rvaVertical.notifyDataSetChanged();
            Loading = false;
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    };

    getMoreQuery.addListenerForSingleValueEvent(addtoAdapter);
}
}

This is my Logcat of Loading(boolean), that I kept track of throughout the program because I believe it was a main part of the issue. 这是我的加载Logcat(布尔值),我在整个程序中都会跟踪,因为我认为这是问题的主要部分。 I have attached it below: 我在下面附上:

2019-05-30 10:26:14.590 24930-24970/com.yourgesture.newsocialmediatab I/FirebaseAuth: [FirebaseAuth:] Loading module via FirebaseOptions.
2019-05-30 10:26:14.956 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: onCreateView - Loading = true
2019-05-30 10:26:16.399 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: First get blogs instance - Loading = true
2019-05-30 10:26:16.406 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: First get blogs instance - Loading = true
2019-05-30 10:26:16.534 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Just Entered onScrolled and Loading = false
2019-05-30 10:26:16.539 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Right After getMoreBlogs gets called. Loading = true
2019-05-30 10:26:16.663 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Just Entered onScrolled and Loading = false
2019-05-30 10:26:16.666 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Right After getMoreBlogs gets called. Loading = true
2019-05-30 10:26:16.826 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Just Entered onScrolled and Loading = false
2019-05-30 10:26:16.828 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Right After getMoreBlogs gets called. Loading = true
2019-05-30 10:26:16.976 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Just Entered onScrolled and Loading = false
2019-05-30 10:26:16.977 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Right After getMoreBlogs gets called. Loading = true
2019-05-30 10:26:17.229 24930-24930/com.yourgesture.newsocialmediatab D/Social Media Tab: Just Entered onScrolled and Loading = false

In Your firstEventListener() , 在你的firstEventListener()中,

getReference().child("blogs") will actually fetches whole child data , which will be considered as read operation, even if you are not using it. getReference()。child(“blogs”)实际上将获取整个子数据,即使您没有使用它也将被视为读取操作。

So there will be no any data saving in your approach. 因此,您的方法中不会有任何数据保存。

Let me share one of the approach: 让我分享一下这个方法:

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;
        }
    });
}

Three new variables are important in the above function: mPostsPerPage: It is the Integer constant defined in the MainActivity.java class which specifies how many records will be queried per page. 在上面的函数中有三个新变量很重要:mPostsPerPage:它是MainActivity.java类中定义的Integer常量,它指定每页将查询的记录数。

mIsLoading: It is a boolean defined in the MainActivity that is used to keep track of whether the Firebase Database query is in progress or not. mIsLoading:它是MainActivity中定义的布尔值,用于跟踪Firebase数据库查询是否正在进行中。

Consts.FIREBASE_DATABASE_LOCATION_USERS: It is the constant defined in the Consts.java class where simply the location of the “users” node is stored Consts.FIREBASE_DATABASE_LOCATION_USERS:它是Consts.java类中定义的常量,其中只存储“users”节点的位置

Ref: https://blog.shajeelafzal.com/2017/12/13/firebase-realtime-database-pagination-guide-using-recyclerview/ 参考: https//blog.shajeelafzal.com/2017/12/13/firebase-realtime-database-pagination-guide-using-recyclerview/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 每当我从Firebase加载数据时,RecyclerView都会滚动到底部 - RecyclerView scrolls to bottom whenever I load the data from Firebase 我正在从 firebase Realtime Db 获取数据,并在 recyclerview 问题上获取数据是 Collection.shuffling 在 android studio 中重复相同的项目 - I am getting data from firebase Realtime Db and fetching on recyclerview issue is Collection.shuffling is repeating same item in android studio 从Firebase实时数据库中删除用户数据 - Deleting user data from Firebase realtime database 从 Firebase 实时数据库获取的数据未显示在我的 RecyclerView 中 - Data fetched from Firebase Realtime Database is not displayed in my RecyclerView 无法使用 RecyclerView 查看来自 firebase 的单个用户数据 - Unable to view single user data from firebase using RecyclerView 无法在 Android Studio 中从 Firebase 实时数据库检索数据 - Can't retrieve data from Firebase Realtime db in Android Studio Java使用REST API发送Firebase Realtime数据库的数据问题 - Java send data issue with Firebase Realtime Database using REST API 从 Firebase 实时数据库中为特定用户读取数据 - Reading data from Firebase Realtime Database for a specific user 我正在尝试将 firebase 实时数据库中的数据检索到我的 recyclerview 中,但数据显示 null - I am trying to retrieve data from firebase realtime database into my recyclerview but data is showing null 如何将数据从实时 firebase 数据库中提取到数组中? 我希望将数组中的静态数据更改为 firebase 数据 - How can I pull data from realtime firebase database into an array? I wish to change static data in an array to firebase data
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM