Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView not recycling views if the view count is small

I've been dealing with a strange behavior in Recycler View, if the view count in the adapter is small, in my case with size 5, the views are not being recycled and onBindViewHolder is not called when the view is scrolled back to screen. If i increase the size to 10 views for example, then recycling starts working and onBindViewHolder is called every time a view enters the screen.

XML

<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/swipeRefresh"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <!-- RECYCLER VIEW -->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/eventsList"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.v4.widget.SwipeRefreshLayout>

Recycler view initialization

    LinearLayoutManager llm = new LinearLayoutManager(getActivity());
    llm.setOrientation(LinearLayoutManager.VERTICAL);

    eventsList.setLayoutManager(llm);

    //Sets endless listener
    scrollListener = new EndlessRecyclerOnScrollListener(llm,3,mLastDownloadedPage) {
        @Override
        public void onLoadMore(int current_page) {
            Timber.d("Loading date for page: " + current_page);

            mLastDownloadedPage = current_page;

            //If it's showing cached don't download
            if(showingCached)
                return;

            //Shows snackbar loading view
            showSnackbarLoadingView();

            //Gets events
            getEvents(false);

        }
    };

    //eventsList.addOnScrollListener(scrollListener);

    //Set the adapter
    mAdapter = new EventListAdapter(this,getActivity().getApplicationContext());

    eventsList.setAdapter(mAdapter);

The Adapter

@Override
public EventHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

    Timber.d("Create view holder pos: "+i);

    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_events_row, viewGroup, false);
    return new EventHolder(v,mListener);

}

@Override
public void onBindViewHolder(EventHolder eventHolder, int i) {

    if(mBindListener != null)
        mBindListener.onBind(eventHolder,i);

    Timber.d("Bind view holder pos "+i);

    Event event = eventList.get(i);
    eventHolder.bindEvent(event);

    //Sets the date
    setDate(eventHolder.date, event);

    //Sets the location
    setLocation(eventHolder.distance,event);


}

In the screen there are only 3 visible views, with a size of 5, when i scroll down i can see that the createViewHolder and bindViewHolder is called for position 4 and 5, but when i scroll to top they are not recycled when exit the screen. I can confirm that because by overriding

@Override
public void onViewRecycled(EventHolder holder) {
    super.onViewRecycled(holder);
    Timber.d("onViewRecycled: "+holder.name);
}

no message is logged. However if the view count is increase for example with size 10, everything works fine, the views are recycled and the onBindViewHolder is called for every position.

Is this normal behavior ? If it's how can i save the state of an item view, for example activated state, i used to save the active position in a variable and then used this line to activate the view when it enters the screen using the bind method

        holder.itemView.setActivated(pos == lastSelectedPos);
like image 393
Sergio Serra Avatar asked Sep 03 '15 11:09

Sergio Serra


People also ask

What is the difference between list view and recycler view?

Simple answer: You should use RecyclerView in a situation where you want to show a lot of items, and the number of them is dynamic. ListView should only be used when the number of items is always the same and is limited to the screen size.

How does RecyclerView recycle?

RecyclerView does not allocate an item view for every item in your data source. Instead, it allocates only the number of item views that fit on the screen(Viewport) and it reuses those item layouts as the user scrolls.

Is there an Addheaderview equivalent for RecyclerView?

addItemDecoration(headerDecoration); The decoration is also reusable since there is no need to modify the adapter or the RecyclerView at all.


1 Answers

It is normal behavior, but you can tweak it with:

recyclerView.setItemViewCacheSize(int);

About the second part of the question - you're right! Store the "activated" position as a variable in your adapter. In onBindViewHolder() do something like:

holder.itemView.setActivated(holder.getAdapterPosition() == lastSelectedPos);
like image 194
JoeyJubb Avatar answered Oct 24 '22 18:10

JoeyJubb