0

I have a layout with recyclerview.

In this recyclerview I have 2 types of layouts: regular + loading.

This recyclerview shows a grid of 3x3 items and for every 5 items I do pagination for the next 5. while doing pagination, each 5th item shows loading until that data was received.

However, In the last batch, it loads the last items and it keeps the loading view as the last item.

In order to overcome this, I have to reload the whole recyclerview which seems wrong to me.

How can I update the view type of the last item when it is the last batch?

My code looks as follows:

public class MoreItemsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List<DiscoverItems> discoverItems;
    private FirebaseFirestore db;
    private FirebaseAuth auth;

    private boolean isLoadingFlag;

    interface OnDiscoverItemClickListener {
        void onClick(DiscoverItems discoverItems);
    }

    private OnDiscoverItemClickListener listener;

    public MoreItemsAdapter(List<DiscoverItems> discoverItems, Boolean isLoadingFlag, OnDiscoverItemClickListener listener) {
        this.discoverItems = discoverItems;
        this.isLoadingFlag = isLoadingFlag;
        this.listener = listener;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view;

        if (viewType == AppConstants.ITEMS_LOADING_KEY) {
            view = LayoutInflater.from( parent.getContext() ).inflate(
                    R.layout.item_loading_items, parent, false );
            return new LoadingViewHolder( view );
        } else {
            view = LayoutInflater.from( parent.getContext() ).inflate(
                    R.layout.item_item_more,
                    parent,
                    false );
            return new MoreItemsViewHolder( view );
        }

    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
        viewHolder.setIsRecyclable( false );

        if (viewHolder instanceof MoreItemsViewHolder) {
            ((MoreItemsViewHolder) viewHolder).bind( (discoverItems.get( position )) );
        } else if (viewHolder instanceof LoadingViewHolder) {
            showLoadingView( (LoadingViewHolder) viewHolder, position );
        }

    }

    @Override
    public int getItemViewType(int position) {

        if (position == discoverItems.size() - 1 && discoverItems.size() > AppConstants.LOAD_MORE_MORE && isLoadingFlag) {
            return AppConstants.ITEMS_LOADING_KEY;
        } else {
            return AppConstants.ITEMS_REGULAR_KEY;
        }

    }


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

    class MoreItemsViewHolder extends RecyclerView.ViewHolder {

        Button tv_Link;
        CardView cardView;

        private MoreItemsViewHolder(View itemView) {
            super( itemView );
            cardView = itemView.findViewById( R.id.imagecard );
            tv_Link = itemView.findViewById( R.id.tv_Link );
        }

        private void bind(DiscoverItems discoverItems) {
            this.discoverItems = discoverItems;
                DO SOMETHING
        }
    }

    private static class LoadingViewHolder extends RecyclerView.ViewHolder {
        ProgressBar progressBar;

        public LoadingViewHolder(@NonNull View itemView) {
            super( itemView );
            progressBar = itemView.findViewById( R.id.progressBar );
        }
    }

    private void showLoadingView(MoreItemsAdapter.LoadingViewHolder viewHolder, int position) {
    }


}

In my code outside of the adapter, I did the following for the last batch (set the second parameter to false to make it understand that it is regular view):

rv_More.invalidate();
rv_More.scrollToPosition( items.size() - loadingNumber - 1 );

moreItemsAdapter = new MoreItemsAdapter( items, false, listener );
rv_More.getItemAnimator().setChangeDuration( 0 );
rv_More.setAdapter( moreItemsAdapter );
isLoading = true;

Cant I do instead something like:

rv_More.setViewType(position, Type)

Thank you

Ben
  • 1,205
  • 2
  • 18
  • 34

1 Answers1

0

Do not modify your view-holders directly. Instead, if you want to invalidate only specific items in your recycler, do the following with your recycler:

myRecycler.getAdapter().notifyItemChanged(itemPosition);

Be sure that your data properly reflects the change when you call this. It will force the recycler to reload only the specific item that you specify (by position).

Dharman
  • 21,838
  • 18
  • 57
  • 107
Gil Moshayof
  • 16,053
  • 4
  • 41
  • 54
  • Hi Gil, thanks for the answer. The thing is that I don't change the item in that position. I only change the layout. In both cases (loading and regular), the item has some data, however only when it is regular I display it and not the progressbar. I want to change the layout from what I understand. – Ben Mar 30 '21 at 19:12
  • If it's a different layout, then you should be using a different view-holder there, with a different item type. Then, when the item changes from "loading" to something else, when you refresh that position, and assuming you've setup your code this way - the adapter will give a different view-type for that position, and then generate / recycle the appropriate view-holder - without invalidating all the items in the recycler. For more details on how to do this, see here: https://stackoverflow.com/questions/25914003/recyclerview-and-handling-different-type-of-row-inflation/25960103#25960103 – Gil Moshayof Mar 30 '21 at 19:25
  • I added my adapter because I think I mislead it accidentally. – Ben Mar 30 '21 at 19:41
  • Your adapter code looks good. The suggestion above should work. Once the new data comes in, the next time the adapter checks the view-type for that row that was once a loading indicator should now reflect a regular item, and it should update properly. – Gil Moshayof Mar 30 '21 at 21:57
  • I tried to do what you offered from my understanding but it didn't work. Maybe I combined both setAdapter and your offer but eventually it didn't work. Could you give example please? – Ben Mar 30 '21 at 22:18