RecyclerView未附加适配器; 跳过布局。

326

我刚刚在我的代码中实现了RecyclerView,代替了ListView

一切都正常工作,数据也被显示出来了。

但是却记录了错误信息:

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

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

对于以下代码:

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

正如您所看到的,我已经为 RecyclerView 添加了一个适配器。那么为什么我还会不断收到这个错误?

我已经阅读了其他与同一问题相关的问题,但它们都没有提供帮助。


@FreeFlyer94 ArtistArrayAdapter 是一个继承 RecyclerView.Adapter 的类。 - equitharn
16
如果您没有在 RecyclerView 附加到窗口时立即初始化它,那么就可能会遇到此问题。 - yigit
2
@yigit 我正在等待Retrofit下载数据,一旦完成,给定的代码就会运行! - equitharn
1
你可以忽略它,或者在初始化RecyclerView时设置一个空的适配器来摆脱它。 - yigit
5
这个错误有多严重?可以忽略吗?无论如何,我使用setAdapter(null)来避免这个错误。 - priyankvex
显示剩余8条评论
38个回答

285

请确保您从“主”线程调用这些语句,而不是在延迟的异步回调(例如在onCreate()方法中)之内调用它们。

当我从一个“延迟”的方法中调用这些语句时,比如在我的ResultCallback中,就会得到同样的消息。

在我的Fragment中,从ResultCallback方法中调用下面的代码会产生相同的消息。将代码移到应用程序内的onConnected()方法后,消息消失了...

LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
list.setLayoutManager(llm);
list.setAdapter( adapter );

15
但我需要先下载数据然后再显示! - equitharn
113
先设置一个空的适配器,一旦有数据就更新它(这对我有效)。 - Peter
3
那是Yigit建议的! - equitharn
15
你需要先设置一个空的适配器,然后下载数据,调用 mAdapter.notifyDataSetChanged(),这对我有效。 - DomonLee
3
这个解决方案对我没有帮助。实际上,这个主题中的任何解决方案都对我没有帮助。请问有人能够在我的问题这里中查看并回答吗? - Pulak
显示剩余7条评论

53

在我修复了代码中的两个问题之前,我一直收到相同的两个错误消息:

(1) 默认情况下,当您在RecyclerView.Adapter中实现方法时,它会生成:

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

确保您更新代码,使其显示为:

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

很明显,如果您的物品数量为零,则屏幕上不会显示任何东西。

(2) 我没有像顶部答案中所示那样进行操作: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) 编辑:奖励: 同时确保您按照以下方式设置RecyclerView

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

不要这样:

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

我看过一些使用后者方法的教程。虽然它可以工作,但我认为它也会产生这个错误。


1
我的 getItemCount() 看起来像这样 public int getItemCount() { return artists == null ? 0 : artists.size(); },以及LayoutInflater View itemView = LayoutInflater. from(parent.getContext()).inflate(R.layout.fragment_listitem, parent, false); - equitharn
这对我有用:@Override public int getItemCount() { return artists.size(); } - AstonCheah
13
哦天啊,当你回到Stack Overflow并看到一个你已经赞过的答案时,你意识到自己也在做同样愚蠢的事情。再次感谢@Micro。 - androidevil

25

我和你遇到了相同的情况,显示没问题,但是出现了定位错误。 这是我的解决方案: (1)在ON CREATE()中初始化RecyclerView并绑定适配器。


这是我的解决方案: (1)在ON CREATE()中初始化RecyclerView并绑定适配器。
RecyclerView mRecycler = (RecyclerView) this.findViewById(R.id.yourid);
mRecycler.setAdapter(adapter);

(2)当你获取数据时,调用notifyDataStateChanged

adapter.notifyDataStateChanged();

在recyclerView的源代码中,有其他线程来检查数据的状态。

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

            }
        }
    };

在dispatchLayout()函数中,我们发现它存在错误:

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 {

抱歉,在我的版本中,我无法在onCreate中使用"this.findViewById()"来定义RecyclerView。Android Studio禁止这样做(无法解析)。也不允许我使用setContentView。这个答案比较旧,所以我认为这是一个版本问题。我被迫等到onViewCreated时才能设置适配器,然后可以使用findViewById来定义RecyclerView。我一定漏掉了什么! - Nathaniel Hoyt

16

我有一个问题,就是在ScrollView对象中放入RecyclerView会发生一些问题。

经过检查实现,原因似乎如下。如果将RecyclerView放入ScrollView中,则在测量步骤期间其高度未指定(因为ScrollView允许任何高度),结果等于最小高度(根据实现),该最小高度显然为零。

您有几个选项可以解决此问题:

  1. 为RecyclerView设置确定的高度
  2. 将ScrollView.fillViewport设置为true
  3. 或将RecyclerView保持在ScrollView之外。在我看来,这绝对是最好的选择。 如果RecyclerView的高度没有限制-当它放入ScrollView中时就是这种情况-则所有Adapter的视图在垂直方向上都有足够的空间并且一次性全部创建。不再进行视图回收,这有点破坏了RecyclerView的目的。

(android.support.v4.widget.NestedScrollView也可以采用相同方法)


将ScrollView.fillViewport设置为true解决了我的问题,非常感谢。 - Eman

12

1) 创建一个不执行任何操作的ViewHolder :)

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

2) 再次创建一个什么也不做的RecyclerView :)

// 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) 当你的真正回收器还没有准备好时,只需使用如下的样例。

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

虽然这不是最好的解决方案,但它可行!希望这对您有所帮助。


你好,请问我遇到了同样的错误,但我不知道应该在哪里检查回收器是否准备好传递空适配器,并且我也不知道在哪里可以检查回收器是否已经准备好(传递带有数据的适配器)。 - James
这太棒了,这是一个拖放式的代码片段,链接在这里https://gist.github.com/anonymous/bcf027945f08f40601090c55d6048e21 - nmu

10

当您在创建过程中未设置适配器时,就会发生这种情况:

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

只需在onCreate中设置适配器并使用空数据,当您有数据时调用:

mAdapter.notifyDataSetChanged();

请确保在onCreate方法中设置CustomAdapter构造函数中的数据。 - Mohit Singh

6

检查一下是否在您的适配器中忘记调用此方法

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

6
在 Kotlin 中,我们遇到了这个奇怪的不合逻辑的问题。
这样做不起作用:
 mBinding.serviceProviderCertificates.apply {
            adapter = adapter
            layoutManager =  LinearLayoutManager(activity)
        }

虽然这样有效:

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

一旦我有更多的下班时间,我会分享更多的见解。


1
我很震惊,这正是我遇到的实际问题。确实非常奇怪。 - Makalele
哇,很奇怪。更奇怪的是,如果你用letalso或者run替换apply,它也能正常工作。 - SVP
是的,它对我有效! - oyeraghib

5

请确保通过以下方式为您的RecyclerView设置布局管理器:

mRecyclerView.setLayoutManager(new LinearLayoutManager(context));

你不仅可以使用 LinearLayoutManager,还可以使用其他布局管理器


4
如果您在片段中使用RecyclerView并从其他视图中膨胀它,请确保将RecyclerView绑定到其根视图时膨胀整个片段视图。我正确地连接和执行适配器的所有操作,但我从未进行绑定。这个@Prateek Agarwal提供的答案对我很有帮助,但这里还有更多解释。 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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接