How to send pagination requests to firebase for endlessly scrollable recyclerview - android

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

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)

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

Related

Images are not showing after implementing Pagination in my RecyclerView

I have implemented Pagination in my RecyclerView but after implementing pagination the images are not showing up
Ok I have implemented this pagination answer
Ok because the answer above is for LinearLayoutManager and I'm using StaggeredGridLayoutManager I have done some modifications in the addOnScrollListener
I have only included the necessary code of Home_Fragment.java so it doesn't get confusing
and long but if you want more references to the code please tell me I
will update the question
Home_Fragment.java
private int previousTotal = 0;
private final int visibleThreshold = 5;
private RecyclerView postRecyclerView;
private boolean loading = true;
private int firstVisibleItem, 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);
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
postRecyclerView.setLayoutManager(
staggeredGridLayoutManager
);
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 (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
getData();
loading = true;
}
}
});
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();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
PostAdapter_Home.java
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 as requested
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;
}
}

How to use recyclerview:1.2.0-alpha02 for saving and restoring recyclerview position

I'm searching on how can I save and restore the recycler view position for my app (never tried to implement saving and restoring the position of recycler view) and after seeing many different ways to implement I found an interesting way wherewith recyclerview:1.2.0-alpha02 it is done automatically here is a medium article
I have read the article but I didn't know how to exactly implement it in my code
please forgive me for the very unprofessional way I'm writing this because I really don't know how to implement a recycler view that saves the scroll and restores the position
The functionality I want for saving and restoring position is kind of Instagram or youtube or any big social media or app with endless scroll where if u switch between different activities or fragments still the position of the recycler view is maintained when you came back
Here is the code // the code is without any implementation of recyclerview:1.2.0-alpha02 because as I said above I don't know how to implement it
Note:- If anyone wants more references of my code please tell me I
will update the question
and I have used StaggeredGridLayoutManager just mentioning it, in case if it is necessary to know
Home_Fragment.java
private final boolean loading = true;
private final String KEY_RECYCLER_STATE = "recycler_state";
public List<Upload> mUploads;
PostAdapter_Home postsAdapter;
ShimmerFrameLayout shimmerFrameLayout;
private RecyclerView postRecyclerView;
// private Parcelable listState;
private int pastVisibleItems, visibleItemCount, totalItemCount;
// Boolean isScrolling = false;
// int currentItems, totalItems, scrolledOutItems;
#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 // I have 3 rows
);
// 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();
getData();
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);
}
}
//notify the adapter
postsAdapter.notifyDataSetChanged();
// loading = true;
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
// loading = true;
}
});
}
PostAdapter_Home.java
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 static class PostViewHolder extends RecyclerView.ViewHolder {
private final ShapeableImageView imageView;
public PostViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imagePostHome);
}
}
}

How to implement endless scroll (pagination) in recyclerview with StaggeredGridLayoutManager

Hello there I have a recyclerview with images loaded from firebase I want to implement endless scroll but the issue I'm getting is with StaggeredGridLayoutManager and I have to use it I cant replace it with grid-layout
Note:- I have seen other answers on this topic but the majority of
answers are for LinearLayoutManager and some for GridLayout but there
is only one answer I found for StaggeredGridLayoutManager which I don't
know why it's not working for me
If you want more references of the code please tell me I will update
the question
Profile_Fragment.java
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile, container, false);
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
ImageView accountSettings = view.findViewById(R.id.account_Settings);
RelativeLayout relativeLayout = view.findViewById(R.id.snipet_profile);
profilePhoto = relativeLayout.findViewById(R.id.circleImageView);
editProfileButton = relativeLayout.findViewById(R.id.edit_profile_button);
uploadImageButton = view.findViewById(R.id.upload_image_profile);
progressBar = view.findViewById(R.id.progressBar_Profile);
editProfileButton.setOnClickListener(v -> {
Fragment edit_profile = new Edit_Profile();
assert getFragmentManager() != null;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, edit_profile);
transaction.addToBackStack(String.valueOf(edit_profile));
transaction.commit();
});
uploadImageButton.setOnClickListener(v -> {
BottomSheet_Upload bottomSheetSettings = new BottomSheet_Upload();
bottomSheetSettings.show(requireActivity().getSupportFragmentManager(), bottomSheetSettings.getTag());
});
accountSettings.setOnClickListener(
v -> {
BottomSheet_Settings bottomSheetSettings = new BottomSheet_Settings();
bottomSheetSettings.show(requireActivity().getSupportFragmentManager(), bottomSheetSettings.getTag());
}
);
postRecyclerView = view.findViewById(R.id.postRecyclerViewProfile);
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
postRecyclerView.setLayoutManager(
staggeredGridLayoutManager // I have 3 rows
);
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");
}
}
}
});
postRecyclerView.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.VISIBLE);
initImageLoader();
setProfileImage();
mUploads = new ArrayList<>();
postsAdapter = new PostAdapter(getContext(), mUploads);
postRecyclerView.setAdapter(postsAdapter);
postsAdapter.setOnItemClickListener(Profile_Fragment.this);
return view;
}
private void initImageLoader() {
UniversalImageLoader universalImageLoader = new UniversalImageLoader(getContext());
ImageLoader.getInstance().init(universalImageLoader.getConfig());
}
private void setProfileImage() {
String imgUrl = "www.64.media.tumblr.com/1276b4edef49034af70bda14325385e3/d8872c747cafa206-96/s500x750/aa915fc49a84b5295f0cd44145d655b66eb906a6.jpg";
UniversalImageLoader.setImage(imgUrl, profilePhoto, null, "https://");
}
private void getData() {
mStorage = FirebaseStorage.getInstance();
databaseEventListener = databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
progressBar.setVisibility(View.GONE);
postRecyclerView.setVisibility(View.VISIBLE);
mUploads.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Upload upload = dataSnapshot.getValue(Upload.class);
Objects.requireNonNull(upload).setmKey(dataSnapshot.getKey());
mUploads.add(upload);
}
}
//notify the adapter
postsAdapter.notifyDataSetChanged();
loading = true;
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
loading = true;
}
});
}
Update 1
The main question code is changed with the current answer and Added the adapter class as requested
Problem
After implementing the answer there are no errors but the images are not loading in so I have updated the main code with the added answer
PostAdapter.java
public class PostAdapter extends RecyclerView.Adapter<PostAdapter.PostViewHolder> {
public static List<Upload> mUploads;
public Context mcontext;
private OnItemClickListener mListener;
/* ShimmerFrameLayout shimmerFrameLayout; */
public PostAdapter(Context context, List<Upload> uploads) {
mUploads = uploads;
mcontext = context;
}
#NonNull
#Override
public PostViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view;
LayoutInflater.from(mcontext).inflate(R.layout.post_item_container_profile, parent, false);
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_item_container_profile, parent, false);
return new PostViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull PostViewHolder holder, int position) {
Upload uploadCurrent = mUploads.get(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);
Glide.with(mcontext)
.load(uploadCurrent.getmImageUrl())
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.placeholder(shimmerDrawable)
.centerCrop()
.fitCenter()
.into(holder.imageView);
}
#Override
public int getItemCount() {
return mUploads.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public interface OnItemClickListener {
void onClick(View view);
void onItemClick(int position);
void onDeleteClick(int position);
}
public class PostViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener {
ShapeableImageView imageView;
PostViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imagePost);
itemView.setOnClickListener(this);
itemView.setOnCreateContextMenuListener(this);
}
#Override
public void onClick(View v) {
if (mListener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
mListener.onItemClick(position);
}
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuItem delete = menu.add(Menu.NONE, 2, 2, "Delete");
delete.setOnMenuItemClickListener(this);
}
#Override
public boolean onMenuItemClick(MenuItem item) {
if (mListener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
if (item.getItemId() == 2) {
mListener.onDeleteClick(position);
return true;
}
}
}
return false;
}
}
}
For your first problem you already have a solution.
StaggeredGridLayoutManager staggeredGridLayoutManager = new
StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
postRecyclerView.setLayoutManager(
staggeredGridLayoutManager // I have 3 rows
);
For second problem:
postRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener({
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
visibleItemCount = staggeredGridLayoutManager .getChildCount();
totalItemCount = staggeredGridLayoutManager .getItemCount();
int[] firstVisibleItems = null;
firstVisibleItems = mLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);
if(firstVisibleItems != null && firstVisibleItems.length > 0) {
pastVisibleItems = firstVisibleItems[0];
}
if (loading) {
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
loading = false;
getData()
}
}
}
});
..........
..........
private void getData() {
mStorage = FirebaseStorage.getInstance();
databaseEventListener = databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
progressBar.setVisibility(View.GONE);
postRecyclerView.setVisibility(View.VISIBLE);
mUploads.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Upload upload = dataSnapshot.getValue(Upload.class);
Objects.requireNonNull(upload).setmKey(dataSnapshot.getKey());
mUploads.add(upload);
}
}
//notify the adapter
postsAdapter.notifyDataSetChanged();
loading = true;
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
loading = true;
}
});
}
You might have to call the getData() initially in your onCreate() so that some data loads up on the screen and you have a scroll behavior.
Update:
The second parameter in a StaggeredGridLayoutManager is orientation so instead of context you have to pass orientation StaggeredGridLayoutManager.VERTICAL.

Image Duplication Recyclerview

Adapter class
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.MyHolder> {
private RecyclerviewListener mlistener;
private Context context;
private ArrayList<ItemModel> data = new ArrayList<>();
public ItemAdapter(Context context, ArrayList<ItemModel> data, RecyclerviewListener mlistener) {
this.mlistener = mlistener;
this.context = context;
this.data = data;
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v;
LayoutInflater inflater = LayoutInflater.from(context);
v = inflater.inflate(R.layout.item_adapter, parent, false);
final ItemAdapter.MyHolder myHolder = new ItemAdapter.MyHolder(v);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mlistener.onClick(view, myHolder.getAdapterPosition());
}
});
return myHolder;
}
#Override
public void onBindViewHolder(#NonNull final MyHolder holder, int position) {
ItemModel i = data.get(position);
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.image_holder2);
// make sure Glide doesn't load anything into this view until told otherwise
// remove the placeholder (optional); read comments below
holder.imageView.setImageDrawable(null);Glide.with(context).setDefaultRequestOptions(requestOptions).load(i.getImage1()).into(holder.imageView); }
#Override
public int getItemCount() {
return data.size();
}
class MyHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public MyHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
}
}}
*Whenever i scroll down with speed .Recyclerview show same item twice i tried many solution but no one is working *
method used first to retrieve data and get last retrieved document ie lastVisible variable
private void getData() {
Query data = firestore.collection("Madhya Pradesh").document(cityname).collection("Product").document(category).collection("View").limit(3);
data.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
QuerySnapshot d = task.getResult();
lastVisible = d.getDocuments()
.get(d.size() - 1);
for (DocumentSnapshot doc : task.getResult()) {
ItemModel item = new ItemModel();
if (doc.getString("Image1") != null) {
item.setImage1(doc.getString("Image1"));
} else {
item.setImage1("null");
}
rdata.add(item);
itemAdapter.notifyDataSetChanged();
}
} else {
// error from firebase handle it;
}
}
});
}
query method (Firebase) used to retrieve data while scrolling
private void scroll() {
itemRView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true;
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
currentitem = manager.getChildCount();
totalitem = manager.getItemCount();
scrollOutitem = manager.findFirstVisibleItemPosition();
if (isScrolling && (currentitem + scrollOutitem == totalitem)) {
progressBar.setVisibility(View.VISIBLE);
isScrolling = false;
final Query data = firestore.collection("State").document(cityname).collection("Product").document(category).collection("View").startAfter(lastVisible).limit(2);
data.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
QuerySnapshot d = task.getResult();
lastVisible = d.getDocuments()
.get(d.size() - 1);
if (task.isSuccessful() && !task.getResult().isEmpty()) {
progressBar.setVisibility(View.GONE);
for (DocumentSnapshot doc : task.getResult()) {
ItemModel item = new ItemModel();
if (doc.getString("Image1") != null) {
item.setImage1(doc.getString("Image1"));
} else {
item.setImage1("null");
}
rdata.add(item);
itemAdapter.notifyDataSetChanged();
}
}
}
});
}
}
});
}
The issue could be in the scrolling procedure.
When you're scrolling the RecyclerView re-binds the Holder and execute the "onBindViewHolder(..)" so if you just want to load the new visible rows (without doing nothing special) during scrolling you can remove the scrolling procedure.

LoadMore Recycler View From Api

I have Recycler view in Android and I need to implement load more at recycler view, I searched over internet but failed to solve my problem, this is my code please help
This is the adapter
public class NewsReycelerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
List<String> Dates , Titles , Details , Images;
public static String NewsDetail,NewsDate ,NewsTitle;
public final int TYPE_NEWS = 0;
public final int TYPE_LOAD = 1;
private int visibleThreshold = 2;
private int lastVisibleItem, totalItemCount;
private boolean loading;
private OnLoadMoreListener onLoadMoreListener;
public NewsReycelerViewAdapter(RecyclerView recyclerView,Context context , List<String> stringsDate , List<String> stringTitles , List<String> stringDetails ,List<String> stringImage,final JPANewsFragment fragment) {
this.context = context;
this.Dates = stringsDate;
this.Titles = stringTitles;
this.Details = stringDetails;
this.Images = stringImage;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
fragment.getHtmlNewsData("1");
loading = true;
}
}
});
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType==TYPE_NEWS){
return new Item_Holder(inflater.inflate(R.layout.news_adapter_item,parent,false));
}else{
return new LoadHolder(inflater.inflate(R.layout.item_loading,parent,false));
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((Item_Holder)holder).Date.setText(Dates.get(position));
((Item_Holder)holder).Title.setText(Titles.get(position));
NewsDetail = Details.get(position);
NewsDate = Dates.get(position);
NewsTitle = Titles.get(position);
((Item_Holder)holder).itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity)context).changeFragmentMethod(new NewsDetailsFragment(),context.getResources().getString(R.string.news_details));
}
});
}
#Override
public int getItemCount() {
return Dates == null ? 0 : Dates.size();
}
//////////////////////////////////////////////////////////////////////////////////
public class Item_Holder extends RecyclerView.ViewHolder {
TextView Title , Date ;
ImageView jpaThumbnail;
public Item_Holder(View itemView) {
super(itemView);
Title = (TextView) itemView.findViewById(R.id.textView_title);
Date = (TextView) itemView.findViewById(R.id.textView_date);
jpaThumbnail = (ImageView) itemView.findViewById(R.id.thumbnail);
}
}
static class LoadHolder extends RecyclerView.ViewHolder{
public LoadHolder(View itemView) {
super(itemView);
}
}
#Override
public int getItemViewType(int position) {
return Dates.get(position) != null ? TYPE_NEWS : TYPE_LOAD;
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.onLoadMoreListener = mOnLoadMoreListener;
}
public void setLoaded() {
loading = false;
}
}
First api have 10 item and when user swipes, I need to load more from another page,
and this is the code written in my main activity
newsReycelerViewAdapter = new NewsReycelerViewAdapter(recyclerViewNews,context, stringsDate, stringsTitle, stringsDetails,stringsImages,new JPANewsFragment());
recyclerViewNews.setLayoutManager(new LinearLayoutManager(context));
recyclerViewNews.setAdapter(newsReycelerViewAdapter);
loadingProgressBar.setVisibility(View.GONE);
newsReycelerViewAdapter.setLoaded();
newsReycelerViewAdapter.notifyDataSetChanged();
Please let me know how to solve this issue.
First add a addOnScrollListener() for your RecyclerView and detect scroll down
recyclerViewNews.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) {
Log.e("test","reached the last element of recyclerview");
visibleItemCount = mLinearLayoutManager.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
pastVisiblesItems = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
fetchData();
}
}
}
}
});
Second Create a function fetchData() to add more data to your adapter
then call on newsReycelerViewAdapter.notifyDataSetChanged(); to notify the dataset change and change loading=true
On your activity main create fields as
int pastVisiblesItems, visibleItemCount, totalItemCount;
boolean loading = true;
Here is example for Simple Implementation of LoadMore RecyclerView using a Simple Library compiled from the various sources.
Add this line in build.gradle
implementation 'com.hereshem.lib:awesomelib:2.0.1'
Create RecyclerView Layout in Activity with
<com.hereshem.lib.recycler.MyRecyclerView
android:id="#+id/recycler"
app:layoutManager="LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Create a ViewHolder by passing the class that supports
public static class EVHolder extends MyViewHolder<Events> {
TextView date, title, summary;
public EVHolder(View v) {
super(v);
date = v.findViewById(R.id.date);
title = v.findViewById(R.id.title);
summary = v.findViewById(R.id.summary);
}
#Override
public void bindView(Events c) {
date.setText(c.date);
title.setText(c.title);
summary.setText(c.summary);
}
}
Create Items List variable and adapters with very few lines by passing items, class and layout in the adapter
List<Events> items = new ArrayList<>();
MyRecyclerView recycler = findViewById(R.id.recycler);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, items, EVHolder.class, R.layout.row_event);
recycler.setAdapter(adapter);
ClickListener and LoadMore Listener can be added with following lines
recycler.setOnItemClickListener(new MyRecyclerView.OnItemClickListener() {
#Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, "Recycler Item Clicked " + position, Toast.LENGTH_SHORT).show();
}
});
recycler.setOnLoadMoreListener(new MyRecyclerView.OnLoadMoreListener() {
#Override
public void onLoadMore() {
loadData();
}
});
loadData();
After the data is loaded this must be called
recycler.loadComplete();
When no LoadMore is required LoadMore layout can be hidden by calling
recycler.hideLoadMore();
Complete example can be found here
Hope this helps :)
My loadmore function looks like:
private void loadMoreMessages() {
DatabaseReference messageRef = mRootRef.child("messages").child(mThemaID);
Query messageQuery = messageRef.orderByKey().endAt(mLastKey).limitToLast(10);
messageQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Messages message = dataSnapshot.getValue(Messages.class);
String messageKey = dataSnapshot.getKey();
if(!mPrevKey.equals(messageKey)){
messagesList.add(itemPos++, message);
}else {
mPrevKey = mLastKey;
}
if(itemPos == 1){
mLastKey = messageKey;
}
mAdapter.notifyDataSetChanged();
mLinearLayout.scrollToPositionWithOffset(itemPos-1, 0);
mRefreshLayout.setRefreshing(false);
}
#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) {
}
});
}
and the listener:
mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
mCurrentPage++;
itemPos = 0;
loadMoreMessages();
}
});
maybe you can do something with this

Categories

Resources