Support RecyclerView doesn't show anything until touched

AndroidAndroid Recyclerview

Android Problem Overview


I'm using the support RecyclerView in my app, and I see the most bizarre thing. It doesn't display any items until I touch to scroll. Then, all of a sudden, the RecyclerView populates itself. I have verified that the list backing the adapter is populated, and that onCreatViewHolder and onBindViewHolder are never called until a touch event.

Here's how I set up the recyclerview:

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Drawable divider = new ColorDrawable(ProfileInfo.getCurrentProfileColor());
        mInboxList.addItemDecoration(new DividerItemDecoration(getActivity(), divider, false));
        mInboxList.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
        mInboxList.setAdapter(new InboxAdapter(getActivity(), new ArrayList<Conversation>()));
        new AsyncTask<Void, Void, List<Conversation>{

              public List<Conversation> doInBackground(...){
                   //load the conversations
                   return conversations;
              }

              public void onPostExecute(List<Conversation> conversations){
                   ((InboxAdapter) mInboxList.getAdapter()).clear(false);
                   ((InboxAdapter) mInboxList.getAdapter()).addAll(conversations);

              }

        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }

Here's a gist of my adapter:

public class InboxAdapter extends RecyclerView.Adapter<InboxAdapter.ViewHolder> {
    List<Conversation> mConversations; //initialized in contructor

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = mInflater.inflate(R.layout.inbox_item, parent, false);
        ViewHolder holder = new ViewHolder(v);
        Log.d(LOG_TAG, "oncreateviewholder : " + viewType); //never called when I first bind the adapter
        return holder;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        final Conversation item = mConversations.get(position);
        Log.d(LOG_TAG, "binding " + position);
        ...
    }

    @Override
    public int getItemCount() {
        Log.d(LOG_TAG, "item count: " + mConversations.size());
        return mConversations.size();
    }

    /**
     * Empties out the whole and optionally notifies
     */
    public void clear(boolean notify) {
        mConversations.clear();
        if (notify) {
            notifyDataSetChanged();
        }
    }

    public void addAll(List<Conversation> conversations) {
        mConversations.addAll(conversations);
        notifyDataSetChanged();
    }


}

Here's the layout file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingTop="?attr/actionBarSize">

    
    <android.support.v7.widget.RecyclerView
        android:id="@+id/lv_inbox"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        ></android.support.v7.widget.RecyclerView>
</RelativeLayout>

I'm using recyclerview-v7:21.0.3 running on a Moto X with version 4.4.4.

EDIT: Smooth scrolling at the end of the onPostExecute seems to resolve the issue:

if (mInboxList.getAdapter().getItemCount() > 0) {
    mInboxList.smoothScrollToPosition(0);
}

Android Solutions


Solution 1 - Android

If anyone else is having this issue using RxJava and Retrofit, I solved this issue by adding the .observeOn(AndroidSchedulers.mainThread()) operator into my method chain before subscribing. I had read this was taken care of by default, and thus not explicitly necessary, but I guess not. Hope this helps.

Example:

public void loadPhotos() {
    mTestPhotoService.mServiceAPI.getPhotos()
                                 .subscribeOn(Schedulers.io())
                                 .observeOn(AndroidSchedulers.mainThread())
                                 .subscribe(photoList -> mRecyclerActivity.OnPhotosLoaded(photoList));
}

Solution 2 - Android

In my case only this worked:

recyclerView.smoothScrollToPosition(arrayModel.size-1); // I am passing last position here you can pass any existing position

RecyclerView was showing data only when I scroll it. So instead of user to manually scroll I have added above line which will scroll the recyclerView programmatically .

Solution 3 - Android

So at first, just like everybody else I just added:

recyclerView.smoothScrollToPosition(0)

and it worked pretty much good enough, however it wasn't nice and you had to remember to add it every time. and I then I followed @SudoPlz comment and answer on another question and it also worked too, you have to extend RecyclerView and override requestLayout:

private boolean mRequestedLayout = false;

@SuppressLint("WrongCall")
@Override
public void requestLayout() {
    super.requestLayout();
    // We need to intercept this method because if we don't our children will never update
    // Check https://stackoverflow.com/questions/49371866/recyclerview-wont-update-child-until-i-scroll
    if (!mRequestedLayout) {
        mRequestedLayout = true;
        this.post(() -> {
            mRequestedLayout = false;
            layout(getLeft(), getTop(), getRight(), getBottom());
            onLayout(false, getLeft(), getTop(), getRight(), getBottom());
        });
    }
}

while still, I would have preferred this to fixed after 4, 5 years, however, this was a good workaround, and you won't forget about them in your view.

Solution 4 - Android

i'm also suffering from same issue for 2 days now its done after add this line.

adapter.notifyDataSetChanged() //after notify adapter add this one mRecyclerView.smoothScrollToPosition(list.size-1)

Solution 5 - Android

In my case it's only happen on Android 6. above this version I didn't had any problems. So what I've found to work is to use recyclerView.scrollBy(0, 0). Check it maybe it will work for you too.

Solution 6 - Android

Since this is still happening, here is an specific fixed instance in case it helps someone:

  • It happened only when the cell view contains a WebView.

The fix:

  • Call setIsRecyclable(false) from the ViewHolder

Solution 7 - Android

This is a bit late, but in my case I had a recylerview inside a viewpager (TabView) that was inside another viewpager (using BottomNavigationView) and smooth scrolling didn't change anything.

However, I noticed that I had the recylerview set with Visibility GONE when the layout was drawn, so the solution was:

  1. Setting the recyclerview to Visibility VISIBLE on xml layout (so it's draw completely when the TabView is set);
  2. When the adapter is set (linked to observable with room), i do:
new Handler(Looper.getMainLooper()).postDelayed(() -> {

     binding.recyclerView.scrollToPosition(0);

}, getResources().getInteger(android.R.integer.config_shortAnimTime));

Solution 8 - Android

You would have to run the stuff you do in onPostExecute on the UI thread so that the RecyclerView gets redrawn. That's why the smooth scrolling works, because that is running on the UI thread and therefore causing the view to redraw.

Solution 9 - Android

It's most likely because you're not calling the correct notification methods of RecyclerView.Adapter. You have a much more granular interface for this than you previously had in ListAdapters. For example, in addAll() you should call notifyItemRangeInserted(oldConversationsSize, conversations.size()) instead of notifyDataSetChanged

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWindsurferOakView Question on Stackoverflow
Solution 1 - AndroidCarter HudsonView Answer on Stackoverflow
Solution 2 - AndroidSuraj VaishnavView Answer on Stackoverflow
Solution 3 - AndroidAmin KeshavarzianView Answer on Stackoverflow
Solution 4 - AndroidHandyPawanView Answer on Stackoverflow
Solution 5 - Androiduser3193413View Answer on Stackoverflow
Solution 6 - AndroidBenoitView Answer on Stackoverflow
Solution 7 - AndroidManuel RegoView Answer on Stackoverflow
Solution 8 - AndroidrobocabView Answer on Stackoverflow
Solution 9 - AndroidMarcus Forsell StahreView Answer on Stackoverflow