Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send pagination requests to firebase for endlessly scrollable recyclerview

I'm trying to include pagination in my app what I want that for eg in my firebase I have 500 images that are to be shown in the recycler view what I want is first 10 or 15 images are loaded in the recycler view at the beginning and when the user reaches to the end of the last item(image) it loads next 10 images (just like Instagram or facebook )

Note:- if anyone wants more reference of my code please tell me I will update my question

Here is my code

Home_Fragment.java

private boolean loading = true;
    private int pastVisibleItems, visibleItemCount, totalItemCount;

    @SuppressLint("SourceLockedOrientationActivity")
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_home, container, false);
        requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        MaterialToolbar materialToolbar = view.findViewById(R.id.toolbar);
        materialToolbar.setOnMenuItemClickListener(toolbarItemClickListener);
        postRecyclerView = view.findViewById(R.id.recyclerViewHome);
        shimmerFrameLayout = view.findViewById(R.id.shimmerEffect);
//        this is for one item per scroll
//        SnapHelper snapHelper = new PagerSnapHelper();
//        snapHelper.attachToRecyclerView(verticalRecyclerView);
        postRecyclerView.setAdapter(postsAdapter);
//        listState = savedInstanceState.getParcelable("ListState");

        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
        postRecyclerView.setLayoutManager(
                staggeredGridLayoutManager
        );
        getData();


        postRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {

                visibleItemCount = staggeredGridLayoutManager.getChildCount();
                totalItemCount = staggeredGridLayoutManager.getItemCount();
                int[] firstVisibleItems = null;
                firstVisibleItems = staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);
                if (firstVisibleItems != null && firstVisibleItems.length > 0) {
                    pastVisibleItems = firstVisibleItems[0];
                }

                if (loading) {
                    if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
                        loading = false;
                        getData();
                        Log.d("tag", "LOAD NEXT ITEM");
                    }
                }
            }
        });
//        setupFirebaseAuth();
        shimmerFrameLayout.startShimmer();
        mUploads = new ArrayList<>();
        postsAdapter = new PostAdapter_Home(getContext(), mUploads);
        postRecyclerView.setAdapter(postsAdapter);
        postRecyclerView.scrollToPosition(Home_Fragment.saved_position);
        return view;
    }


    private void getData() {
        databaseReference.addValueEventListener(new ValueEventListener() {
            @SuppressLint("NotifyDataSetChanged")
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if (snapshot.exists()) {
                    shimmerFrameLayout.stopShimmer();
                    shimmerFrameLayout.setVisibility(View.GONE);
                    postRecyclerView.setVisibility(View.VISIBLE);
                    mUploads.clear();
                    for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                        Upload upload = dataSnapshot.getValue(Upload.class);
                        assert upload != null;
                        upload.setmKey(dataSnapshot.getKey());
                        mUploads.add(upload);


                    }

                }
                postsAdapter.setUploads(mUploads);

                //notify the adapter
                postsAdapter.notifyDataSetChanged();
                loading = true;
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                loading = true;
            }
        });
    }

PostAdapter_Home.java // Adapter Class

public class PostAdapter_Home extends RecyclerView.Adapter<PostAdapter_Home.PostViewHolder> {
    public static List<Upload> mUploads;
    public Context mcontext;

    public PostAdapter_Home(Context context, List<Upload> uploads) {
        mUploads = uploads;
        mcontext = context;
    }


    @NonNull
    @Override
    public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view;
        view = LayoutInflater.from(mcontext).inflate(R.layout.ex_home, parent, false);
        return new PostViewHolder(view);

    }

    @Override
    public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
        Shimmer shimmer = new Shimmer.ColorHighlightBuilder()
                .setBaseColor(Color.parseColor("#F3F3F3"))
                .setBaseAlpha(1)
                .setHighlightColor(Color.parseColor("#E7E7E7"))
                .setHighlightAlpha(1)
                .setDropoff(50)
                .build();
        ShimmerDrawable shimmerDrawable = new ShimmerDrawable();
        shimmerDrawable.setShimmer(shimmer);
        Upload uploadCurrent = mUploads.get(position);
        Glide.with(mcontext)
                .load(uploadCurrent.getmImageUrl())
                .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
                .placeholder(shimmerDrawable)
                .centerCrop()
                .fitCenter()
                .into(holder.imageView);

//        holder.imageView.setOnClickListener(view -> changeScaleType(holder, position));

    }


    @Override
    public int getItemCount() {
        return mUploads.size();
    }

    public void setUploads(List<Upload> uploads){
        mUploads=uploads;
    }
    public static class PostViewHolder extends RecyclerView.ViewHolder {

        private final ShapeableImageView imageView;

        public PostViewHolder(@NonNull View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.imagePostHome);

        }


    }
}

Update // Added Upload.java file code as requested in the comment section

Upload.java

package com.example.myappnotfinal.AdaptersAndMore;

import com.google.firebase.database.Exclude;

public class Upload {
    private String mImageUrl;
    private String mKey;
    private String mUserName;
    private String mComment;

    public Upload() {

    }

    public Upload(String imageUrl) {
        mImageUrl = imageUrl;
    }

    public String getmUserName() {
        return mUserName;
    }

    public void setmUserName(String mUserName) {
        this.mUserName = mUserName;
    }

    public String getmComment() {
        return mComment;
    }

    public void setmComment(String mComment) {
        this.mComment = mComment;
    }

    public String getmImageUrl() {
        return mImageUrl;
    }

    public void setmImageUrl(String mImageUrl) {
        this.mImageUrl = mImageUrl;
    }

    @Exclude
    public String getmKey() {
        return mKey;
    }

    @Exclude
    public void setmKey(String Key) {
        this.mKey = Key;
    }
}
like image 811
Vasant Raval Avatar asked Oct 25 '21 06:10

Vasant Raval


People also ask

Is RecyclerView scrollable?

To help you build apps with lists, Android provides the RecyclerView . RecyclerView is designed to be very efficient, even with large lists, by reusing, or recycling, the views that have scrolled off the screen.

What is RecyclerView pagination?

Pagination with Recyclerview allows the user to see the latest content as page by page. As we load the next 'page' by the time users scroll to the bottom, more content is loaded and available.

How to implement pagination of Firebase Realtime Database in recyclerview?

Here is Android library to implement Pagination of Firebase Realtime Database in RecyclerView. The Sample app is available in app/ directory that demonstrates feature of this library. Step by step description is given here FirebaseRecyclerPagingation Library binds Firebase Realtime Database Query to a RecyclerView by loading Data in pages.

How to support pagination with FireStore database using firebaseui-Android library?

To support pagination with Firestore database FirebaseUI-Android library has provided the API for that purpose as FirestorePagingAdapter but still, it’s not available for Realtime Database. Firebase Realtime Database is also important in some type of applications such as chatting apps. Because its speed is faster than Firestore.

How to create a paginated list of posts in Android using Firebase?

First of all, go to Firebase Console and create a new Android Project. Download configuration file i.e. google-services.json and place it in the /app directory. In this app, you are showing a paginated list of Posts. Posts will load in RecyclerView.

What is pagination in Android recyclerview?

Pagination is one of the most important factors which helps to reduce the loading time inside our app and increase the performance of our data which is represented in the form of Lists. In this article, we will take a look at adding pagination in our Android RecyclerView .


Video Answer


2 Answers

First you should separate fetching data logic from UI. Then your scroll controller (RecyclerView) should control which images should be called to download (so when it's loaded it should ask for first batch of images, when scroll happens - ask for another batch, etc.). And downloading and caching images is not a trivial task, that's why we have Glide and Coil in Android world.

As a side note please take a look at https://developer.android.com/topic/libraries/architecture/paging/v3-paged-data and https://developer.android.com/topic/libraries/architecture/paging.

Please check what you're adding to the list of mUploads because every time you add items, you clear the list upfront mUploads.clear(); which may be not what you wanted.

Some notes:

  • dont make it static public static List<Upload> mUploads;
  • don't need to store mcontext, Context is already there
  • strip the problem out of unncessary stuff (e.g. drop shimmer, fix the problem, add shimmer when fixed)
like image 188
Marian Paździoch Avatar answered Oct 20 '22 06:10

Marian Paździoch


Here what you need to do is setLimit for pagination process.

Here is and example:

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

So here you need to send last node id each time to get new list. After getting response just add your data to ArrayList or what ever logic you are using. Then just update RecyclerView like this:

 blogRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                isScrolling = true;
            }
        }

        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            currentItems = manager.getChildCount();
            totalItems = manager.getItemCount();
            scrollOutItems = manager.findFirstVisibleItemPosition();

            if (isScrolling && (currentItems + scrollOutItems == totalItems) && nextPage != null) {
                isScrolling = false;
                progressBar.setVisibility(View.VISIBLE);
                 getUsers(mlastNodeId);//here your last id will be
            }
        }
    });
}
like image 32
Zeeshan Ali Avatar answered Oct 20 '22 05:10

Zeeshan Ali