[android] recyclerview No adapter attached; skipping layout

Just implemented RecyclerView in my code, replacing ListView.

Everything works fine. The data is displayed.

But error messages are being logged:

15:25:53.476 E/RecyclerView: No adapter attached; skipping layout

15:25:53.655 E/RecyclerView: No adapter attached; skipping layout

for the following code:

ArtistArrayAdapter adapter = new ArtistArrayAdapter(this, artists);
recyclerView = (RecyclerView) findViewById(R.id.cardList);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

As you can see I have attached an adapter for RecyclerView. So why do I keep getting this error?

I have read other questions related to the same problem but none of them help.

This question is related to android android-recyclerview

The answer is


It worked for me.

  1. Do this if you are using the emulator.

android:usesCleartextTraffic="true"

  1. If your cardview xml design is like this,

android.support.v7.widget.CardView

Replace cardview xml design with android x. Must be such;

androidx.cardview.widget.CardView

  1. If your recyclerview xml design is like this,

android.support.v7.widget.RecyclerView

Replace cardview xml design with android x. Must be such;

androidx.recyclerview.widget.RecyclerView


In my situation it was a forgotten component which locates in ViewHolder class but it wasn't located in layout file


Just put code inside onCreate() method

/* Like This*/

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_activity);

    recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    layoutManager = new LinearLayoutManager(YourActivity.this);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setHasFixedSize(true);
    mAdapter = new YourAdapter(YourModelClassObject);
    recyclerView.setAdapter(mAdapter);
}

1) Create ViewHolder that does nothing :)

// SampleHolder.java
public class SampleHolder extends RecyclerView.ViewHolder {
    public SampleHolder(View itemView) {
        super(itemView);
    }
}

2) Again create RecyclerView that does nothing :)

// SampleRecycler.java
public class SampleRecycler extends RecyclerView.Adapter<SampleHolder> {
    @Override
    public SampleHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(SampleHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }
}

3) Now when your real recycler is not ready just use the sample one like below.

RecyclerView myRecycler = (RecyclerView) findViewById(R.id.recycler_id);
myRecycler.setLayoutManager(new LinearLayoutManager(this));
myRecycler.setAdapter(new SampleRecycler());

This is not best solution though but it works! Hope this is helpful.


I had the same problem and realized I was setting both the LayoutManager and adapter after retrieving the data from my source instead of setting the two in the onCreate method.

salesAdapter = new SalesAdapter(this,ordersList);
        salesView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
        salesView.setAdapter(salesAdapter);

Then notified the adapter on data change

               //get the Orders
                Orders orders;
                JSONArray ordersArray = jObj.getJSONArray("orders");
                    for (int i = 0; i < ordersArray.length() ; i++) {
                        JSONObject orderItem = ordersArray.getJSONObject(i);
                        //populate the Order model

                        orders = new Orders(
                                orderItem.getString("order_id"),
                                orderItem.getString("customer"),
                                orderItem.getString("date_added"),
                                orderItem.getString("total"));
                        ordersList.add(i,orders);
                        salesAdapter.notifyDataSetChanged();
                    }

Solved by setting the initialized empty list and adapter at the bottom and calling notifyDataSetChanged when results are fetched.

    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
    recyclerviewItems.setLayoutManager(linearLayoutManager);
    someAdapter = new SomeAdapter(getContext(),feedList);
    recyclerviewItems.setAdapter(someAdapter);

In my case it happened cause i embedded a RecyclerView in a LinearLayout.

I previously had a layout file only containing one root RecyclerView as follows

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:listitem="@layout/fragment_products"

    android:name="Products.ProductsFragment"
    app:layoutManager="LinearLayoutManager"
    tools:context=".Products.ProductsFragment"

    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"/>

I believe the problem is within the 3 lines separated. Anyway, I think its a simple problem, ill be working on it tomorrow; thought i should write what i found before forgetting about this thread.


This happens because the actual inflated layout is different from that which is being referred by you while finding the recyclerView. By default when you create the fragment, the onCreateView method appears as follows: return inflater.inflate(R.layout.<related layout>,container.false);

Instead of that, separately create the view and use that to refer to recyclerView View view= inflater.inflate(R.layout.<related layout>,container.false); recyclerview=view.findViewById(R.id.<recyclerView ID>); return view;


// It happens when you are not setting the adapter during the creation phase: call notifyDataSetChanged() when api response is getting Its Working

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity);


        magazineAdapter = new MagazineAdapter(getContext(), null, this );
        newClipRecyclerView.setAdapter(magazineAdapter);
        magazineAdapter.notifyDataSetChanged();

       APICall();
}

public void APICall() {
    if(Response.isSuccessfull()){
    mRecyclerView.setAdapter(mAdapter);
   }
}
Just move setting the adapter into onCreate with an empty data and when you have the data call:

mAdapter.notifyDataSetChanged();

I have the same situation with you, display is ok, but error appear in the locat. That's my solution: (1) Initialize the RecyclerView & bind adapter ON CREATE()

RecyclerView mRecycler = (RecyclerView) this.findViewById(R.id.yourid);
mRecycler.setAdapter(adapter);

(2) call notifyDataStateChanged when you get the data

adapter.notifyDataStateChanged();

In the recyclerView's source code, there is other thread to check the state of data.

public RecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.mObserver = new RecyclerView.RecyclerViewDataObserver(null);
    this.mRecycler = new RecyclerView.Recycler();
    this.mUpdateChildViewsRunnable = new Runnable() {
        public void run() {
            if(RecyclerView.this.mFirstLayoutComplete) {
                if(RecyclerView.this.mDataSetHasChangedAfterLayout) {
                    TraceCompat.beginSection("RV FullInvalidate");
                    RecyclerView.this.dispatchLayout();
                    TraceCompat.endSection();
                } else if(RecyclerView.this.mAdapterHelper.hasPendingUpdates()) {
                    TraceCompat.beginSection("RV PartialInvalidate");
                    RecyclerView.this.eatRequestLayout();
                    RecyclerView.this.mAdapterHelper.preProcess();
                    if(!RecyclerView.this.mLayoutRequestEaten) {
                        RecyclerView.this.rebindUpdatedViewHolders();
                    }

                    RecyclerView.this.resumeRequestLayout(true);
                    TraceCompat.endSection();
                }

            }
        }
    };

In the dispatchLayout(), we can find there is the error in it:

void dispatchLayout() {
    if(this.mAdapter == null) {
        Log.e("RecyclerView", "No adapter attached; skipping layout");
    } else if(this.mLayout == null) {
        Log.e("RecyclerView", "No layout manager attached; skipping layout");
    } else {

i have this problem , a few time problem is recycleView put in ScrollView object

After checking implementation, the reason appears to be the following. If RecyclerView gets put into a ScrollView, then during measure step its height is unspecified (because ScrollView allows any height) and, as a result, gets equal to minimum height (as per implementation) which is apparently zero.

You have couple of options for fixing this:

  1. Set a certain height to RecyclerView
  2. Set ScrollView.fillViewport to true
  3. Or keep RecyclerView outside of ScrollView. In my opinion, this is the best option by far. If RecyclerView height is not limited - which is the case when it's put into ScrollView - then all Adapter's views have enough place vertically and get created all at once. There is no view recycling anymore which kinda breaks the purpose of RecyclerView .

(Can be followed for android.support.v4.widget.NestedScrollView as well)


These Lines must be in OnCreate:

mmAdapter = new Adapter(msgList);
mrecyclerView.setAdapter(mmAdapter);

I was getting the same two error messages until I fixed two things in my code:

(1) By default, when you implement methods in the RecyclerView.Adapter it generates:

@Override
public int getItemCount() {
    return 0;
}

Make sure you update your code so it says:

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

Obviously if you have zero items in your items then you will get zero things displayed on the screen.

(2) I was not doing this as shown in the top answer: CardView layout_width="match_parent" does not match parent RecyclerView width

//correct
LayoutInflater.from(parent.getContext())
            .inflate(R.layout.card_listitem, parent, false);

//incorrect (what I had)
LayoutInflater.from(parent.getContext())
        .inflate(R.layout.card_listitem,null);

(3) EDIT: BONUS: Also make sure you set up your RecyclerView like this:

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

NOT like this:

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

I have seen some tutorials using the latter method. While it works I think it generates this error too.


Just add the following to RecyclerView

app:layoutManager="android.support.v7.widget.LinearLayoutManager"

Example:

   <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:layout_constraintBottom_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </android.support.v7.widget.RecyclerView>

Make sure you set the layout manager for your RecyclerView by:

mRecyclerView.setLayoutManager(new LinearLayoutManager(context));

Instead of LinearLayoutManager, you can use other layout managers too.


First initialize the adapter

public void initializeComments(){
    comments = new ArrayList<>();

    comments_myRecyclerView = (RecyclerView) findViewById(R.id.comments_recycler);
    comments_mLayoutManager = new LinearLayoutManager(myContext);
    comments_myRecyclerView.setLayoutManager(comments_mLayoutManager);

    updateComments();
    getCommentsData();

}

public void updateComments(){

    comments_mAdapter = new CommentsAdapter(comments, myContext);
    comments_myRecyclerView.setAdapter(comments_mAdapter);
}

When ever there is a change in the dataset set, just call the updateComments method.


In Kotlin we had this weird illogical issue.

This didn't work:

 mBinding.serviceProviderCertificates.apply {
            adapter = adapter
            layoutManager =  LinearLayoutManager(activity)
        }

While this worked:

mBinding.serviceProviderCertificates.adapter = adapter
mBinding.serviceProviderCertificates.layoutManager = LinearLayoutManager(activity)

Once I get more after work hours, I will share more insights.


In your RecyclerView adapter class, for example MyRecyclerViewAdapter, make a constructor with the following params.

MyRecyclerViewAdapter(Context context, List<String> data) {
    this.mInflater = LayoutInflater.from(context); // <-- This is the line most people include me miss
    this.mData = data;
}

mData is the data that you'll pass to the adapter. It is optional if you have no data to be passed. mInflater is the LayoutInflater object that you have created and you use in the OnCreateViewHolder function of the adapter.

After this, you attach the adapter in the MainActivity or wherever you want to on the main/UI thread properly like

MyRecyclerViewAdapter recyclerAdapter;
OurDataStuff mData;

    ....
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Like this:

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerAdapter = new RecyclerAdapter(this, mData); //this, is the context. mData is the data you want to pass if you have any
        recyclerView.setAdapter(recyclerAdapter);
    }
   ....

Check if you have missed to call this method in your adapter

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

I had the same error I fixed it doing this if you are waiting for data like me using retrofit or something like that

Put before Oncreate

private ArtistArrayAdapter adapter;
private RecyclerView recyclerView;

Put them in your Oncreate

 recyclerView = (RecyclerView) findViewById(R.id.cardList);
 recyclerView.setHasFixedSize(true);
 recyclerView.setLayoutManager(new LinearLayoutManager(this));
 adapter = new ArtistArrayAdapter( artists , R.layout.list_item ,getApplicationContext());
 recyclerView.setAdapter(adapter);

When you receive data put

adapter = new ArtistArrayAdapter( artists , R.layout.list_item ,getApplicationContext());
recyclerView.setAdapter(adapter);

Now go in your ArtistArrayAdapter class and do this what it will do is if your array is empty or is null it will make GetItemCount return 0 if not it will make it the size of artists array

@Override
public int getItemCount() {

    int a ;

    if(artists != null && !artists.isEmpty()) {

        a = artists.size();
    }
    else {

        a = 0;

     }

   return a;
}

My problem was my recycler view looked like this

        <android.support.v7.widget.RecyclerView
        android:id="@+id/chatview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
    </android.support.v7.widget.RecyclerView>

When it should have looked like this

       <android.support.v7.widget.RecyclerView
        android:id="@+id/chatview"
        android:layout_width="395dp"
        android:layout_height="525dp"
        android:layout_marginTop="52dp"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="8dp"></android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>

In my case, I was setting the adapter inside onLocationChanged() callback AND debugging in the emulator. Since it didn't detected a location change it never fired. When I set them manually in the Extended controls of the emulator it worked as expected.


I had this error, and I tried to fix for a while until I found the solution.

I made a private method buildRecyclerView, and I called it twice, first on onCreateView and then after my callback (in which I fetch data from an API). This is my method buildRecyclerView in my Fragment:

private void buildRecyclerView(View v) {
        mRecyclerView = v.findViewById(R.id.recycler_view_loan);
        mLayoutManager = new LinearLayoutManager(getActivity());
        ((LinearLayoutManager) mLayoutManager).setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mAdapter = new LoanAdapter(mExampleList);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
}

Besides, I have to modify the method get-Item-Count in my adapter, because On on-Create-View the list is null and it through an error. So, my get-Item-Count is the following:

@Override
    public int getItemCount() {
        try {
            return mLoanList.size();
        } catch (Exception ex){return 0;}

    }

ArtistArrayAdapter adapter = new ArtistArrayAdapter(this, artists);
recyclerView = (RecyclerView) findViewById(R.id.cardList);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);

Just replace above code with this and it should work. What you did wrong is you called setAdapter(adapter) before calling layout manager.


Adding yet another answer since I came across this thread googling the error. I was trying to initialize a PreferenceFragmentCompat but I forgot to inflate the preference XML in onCreatePreferences like this:

class SettingsFragment : PreferenceFragmentCompat() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val inflater = LayoutInflater.from(context)
        inflater.inflate(R.layout.fragment_settings, null)
    }

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        // Missing this line here:
        //   setPreferencesFromResource(R.xml.settings, rootKey)
    }
}

The error was a mystery until I realized that PreferenceFragmentCompat must be using a RecyclerView internally.


This is really a simple error you are getting, there in no need of doing any codes in this. This error occurs due to the wrong layout file used by the activity. By IDE i automatically created a layout v21 of a layout which became a default layout of the activity. all codes I did in the old layout file and new one was only having few xml codes, which led to that error.

Solution: Copy all codes of old layout and paste in layout v 21


This issue is because you are not adding any LayoutManager for your RecyclerView.

Another reason is because you are calling this code in a NonUIThread. Make sure to call this call in the UIThread.

The solution is only you have to add a LayoutManager for the RecyclerView before you setAdapter in the UI Thread.

recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

I was getting same issue, I did every thing correct excepted in xml file:

  • step first 1: initialize recyclerview & List & Adaptor:

    RecyclerView recyclerview;
    List<ModelName> list;
    ProvideBidAdaptor adaptor;
    
  • step 2: bind it in onCreate-

    recyclerview = findByViewId(R.id.providerBidRV);
    recyclerview.setLayoutManager(new LinearLayoutManager(this));
    recyclerview.setHasFixedSize(true);
    list = new ArrayList<>();
    
  • step 3: Where you getting response or list - add list- (i am getting from response)>

    responseList.addAll(response.getResponse());
    adaptor = new ProvideBidAdaptor(this, responseList);
    binding.detailsRV.setAdapter(adaptor);
    

Here is my xml file where i implement RecyclerView: I was forget orientation in LinearLayout, after this correction- RecyclerView attached.

<?xml version="1.0" encoding="utf-8"?>
    <layout>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".activities.Bidding.ProvideBid">

        <include
            android:id="@+id/toolbar"
            layout="@layout/app_toolbar"/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/providerBidRV"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </LinearLayout>
</layout> 

Here is Adaptor:

    public class ProvideBidAdaptor extends RecyclerView.Adapter<ProvideBidAdaptor.ViewHolder> {
    Context context;
    List<Response> responseList;
    DateTime dateTimeInstance = new DateTime();

    public ProvideBidAdaptor(Context context, List<Response> responseList) {
        this.context = context;
        this.responseList = responseList;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.geo_presence_item_list, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        final Response detailsResponse = responseList.get(position);
        if (!detailsResponse.getUserId().isEmpty()) {

            holder.day.setText(detailsResponse.getDay());
            holder.locationType.setText(detailsResponse.getLocationType());

        }

    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView date,locationType;
        CardView provideBidCV;
        LinearLayout dayLLayout,locationTypeLLayout;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            date = itemView.findViewById(R.id.date_value);
            day = itemView.findViewById(R.id.day_value);
            locationType = itemView.findViewById(R.id.locationType_value);

            locationTypeLLayout = itemView.findViewById(R.id.locationTypeLLayout);

        }
    }
}

It happens when you are not setting the adapter during the creation phase:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    ....
}

public void onResume() {
    super.onResume();
    mRecyclerView.setAdapter(mAdapter);
    ....
}

Just move setting the adapter into onCreate with an empty data and when you have the data call:

mAdapter.notifyDataSetChanged();

I lost 16 minutes of my life with this issue, so I'll just admit to this incredibly embarrassing mistake that I was making- I'm using Butterknife and I bind the view in onCreateView in this fragment.

It took a long time to figure out why I had no layoutmanager - but obviously the views are injected so they won't actually be null, so the the recycler will never be null .. whoops!

@BindView(R.id.recycler_view)
RecyclerView recyclerView;

    @Override
public View onCreateView(......) {
    View v = ...;
    ButterKnife.bind(this, v);
    setUpRecycler()
 }

public void setUpRecycler(Data data)
   if (recyclerView == null) {
 /*very silly because this will never happen*/
       LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
       //more setup
       //...
    }
    recyclerView.setAdapter(new XAdapter(data));
}

If you are getting an issue like this trace your view and use something like uiautomatorviewer


I have solved this error. You just need to add layout manager and add the empty adapter.

Like this code:

myRecyclerView.setLayoutManager(...//your layout manager);
        myRecyclerView.setAdapter(new RecyclerView.Adapter() {
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                return null;
            }

            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

            }

            @Override
            public int getItemCount() {
                return 0;
            }
        });
//other code's 
// and for change you can use if(mrecyclerview.getadapter != speacialadapter){
//replice your adapter
//}

For those who use the RecyclerView within a fragment and inflate it from other views: when inflating the whole fragment view, make sure that you bind the RecyclerView to its root view.

I was connecting and doing everything for the adapter correctly, but I never did the binding. This answer by @Prateek Agarwal has it all for me, but here is more elaboration.

Kotlin

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {

    val rootView =  inflater?.inflate(R.layout.fragment_layout, container, false)
    recyclerView = rootView?.findViewById(R.id.recycler_view_id)
    // rest of my stuff
    recyclerView?.setHasFixedSize(true)
    recyclerView?.layoutManager = viewManager
    recyclerView?.adapter = viewAdapter
    // return the root view
    return rootView
}

Java

  @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView= inflater.inflate(R.layout.fragment_layout,container,false);
    recyclerview= rootView.findViewById(R.id.recycler_view_id);
    return rootView;
}