“LayoutManager is already attached to a RecyclerView” 错误。

53

我尝试在布局中有多个RecyclerView,但是我遇到了以下错误:“LayoutManager已经附加到RecyclerView”

Java代码如下:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_squad, container, false);

    Activity parentActivity = getActivity();
    final ObservableScrollView scrollView = (ObservableScrollView) view.findViewById(R.id.squad_scrollview);

    final RecyclerView gkRecyclerView = (RecyclerView) view.findViewById(R.id.gk_recycler);
    final RecyclerView coachRecyclerView = (RecyclerView) view.findViewById(R.id.coach_recycler);

    coachRecyclerView.setAdapter(new SquadRecyclerAdapter(parentActivity, getSquadDummyData(0)));
    coachRecyclerView.setLayoutManager(new MyLinearLayoutManager(parentActivity, LinearLayoutManager.VERTICAL, false));
    coachRecyclerView.setHasFixedSize(false);

    gkRecyclerView.setAdapter(new SquadRecyclerAdapter(parentActivity, getSquadDummyData(1)));
    gkRecyclerView.setLayoutManager(new MyLinearLayoutManager(parentActivity, LinearLayoutManager.VERTICAL, false));
    gkRecyclerView.setHasFixedSize(false);

    scrollView.setTouchInterceptionViewGroup((ViewGroup) parentActivity.findViewById(R.id.container));

    if (parentActivity instanceof ObservableScrollViewCallbacks) {
        scrollView.setScrollViewCallbacks((ObservableScrollViewCallbacks) parentActivity);
    }

    return view;
}

XML 布局代码是:

<com.github.ksoichiro.android.observablescrollview.ObservableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/squad_scrollview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="@dimen/margin_medium"
    >

    <LinearLayout
        android:id="@+id/squad_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/seasons_scrollview"
        android:divider="@drawable/nav_bar_divider"
        android:elevation="@dimen/card_elevation"
        android:orientation="vertical"
        android:showDividers="middle">

        <LinearLayout
            android:id="@+id/coach_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="@dimen/margin_small"
            android:paddingLeft="@dimen/margin_standard"
            android:paddingRight="@dimen/margin_standard"
            android:paddingTop="@dimen/margin_small">

            <TextView
                android:id="@+id/squad_coach_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Coach"
                android:textSize="@dimen/text_size_standard" />

            <android.support.v7.widget.RecyclerView
                android:id="@+id/coach_recycler"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingTop="@dimen/margin_small"
                android:paddingBottom="@dimen/margin_small"
                android:scrollbars="none">

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

        </LinearLayout>

        <LinearLayout
            android:id="@+id/gk_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="@dimen/margin_small"
            android:paddingLeft="@dimen/margin_standard"
            android:paddingRight="@dimen/margin_standard"
            android:paddingTop="@dimen/margin_small">

            <TextView
                android:id="@+id/squad_gk_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Goalkeepers"
                android:textSize="@dimen/text_size_standard" />

            <android.support.v7.widget.RecyclerView
                android:id="@+id/gk_recycler"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingTop="@dimen/margin_small"
                android:paddingBottom="@dimen/margin_small"
                android:scrollbars="none">

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

        </LinearLayout>

        <LinearLayout
            android:id="@+id/def_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="@dimen/margin_small"
            android:paddingLeft="@dimen/margin_standard"
            android:paddingRight="@dimen/margin_standard"
            android:paddingTop="@dimen/margin_small">

            <TextView
                android:id="@+id/squad_def_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Defense"
                android:textSize="@dimen/text_size_standard" />

        </LinearLayout>

        <LinearLayout
            android:id="@+id/mid_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="@dimen/margin_small"
            android:paddingLeft="@dimen/margin_standard"
            android:paddingRight="@dimen/margin_standard"
            android:paddingTop="@dimen/margin_small">

            <TextView
                android:id="@+id/squad_mid_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Midfielders"
                android:textSize="@dimen/text_size_standard" />

        </LinearLayout>

        <LinearLayout
            android:id="@+id/for_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="@dimen/margin_small"
            android:paddingLeft="@dimen/margin_standard"
            android:paddingRight="@dimen/margin_standard"
            android:paddingTop="@dimen/margin_small">

            <TextView
                android:id="@+id/squad_for_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Forwards"
                android:textSize="@dimen/text_size_standard" />

        </LinearLayout>


    </LinearLayout>


</com.github.ksoichiro.android.observablescrollview.ObservableScrollView>

MyLinearLayoutManager是我在网上找到的自定义LinearLayoutManager,旨在解决SDK LinearLayoutManager的wrap-content问题。

我是否可以在单个布局中拥有多个RecyclerView?似乎我不能在一个布局中附加多个LayoutManager。

任何帮助都将非常欢迎 :)


你能更新一下那个LayoutManager的源代码吗? - Eduardo Naveda
我尝试了SDK的LinearLayoutManager,但仍然出现相同的错误。因此,问题不在于自定义的LayoutManager。 - TheoK
9个回答

99

我也遇到了这个问题。我的Activity使用选项卡,有三个片段。当我切换到第三个选项卡,然后返回到第一个(或第二个)选项卡时,就会抛出此错误。

经过大量搜索,我发现可能是垃圾收集器的原因,因为我在使用强引用。

由于LinearLayoutManager构造函数使用活动作为参数(而不是片段),所以选项卡活动在选项卡更改期间保持活动状态。

从类中删除mLinearLayoutManager的本地字段,并使用弱引用,我可以摆脱这个问题:

之前:

public class MyFragment1 extends Fragment
    private LinearLayoutManager linearLayoutManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        linearLayoutManager = new LinearLayoutManager(getActivity());
        (...)
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        (...)
        mRecyclerView.setLayoutManager(linearLayoutManager);
    }
}

我改成了:

public class MyFragment1 extends Fragment {
    // private LinearLayoutManager linearLayoutManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // linearLayoutManager = new LinearLayoutManager(getActivity());
        (...)
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        (...)
        mRecyclerView.setLayoutManager(
           new LinearLayoutManager(getActivity()));
    }
}

1
不仅它能够正常工作,我还成功地实现了在片段显示时根据用户选择更改布局的功能,只需点击一个按钮即可。 - Zvi
1
非常感谢您! - Muhammad
2
有其他的方法吗?因为我需要在我的片段中将LayoutManager作为全局对象使用。 - Kyo Huu
1
如果我需要在Fragment类中使用LayoutManager怎么办?例如,我正在使用它作为scrollListeners。 - Den
1
这样的答案非常罕见,但当它像这个一样明确地解决了我的问题并提供了如此简单、直接的解决方案时,真是让人感到满意。谢谢! - Nathaniel Hoyt
显示剩余6条评论

9

只需要创建一个新实例:

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

9

当我通过Dagger提供LayoutManager时,遇到了这个错误。
解决方案是使用LayoutManager javax.inject.Provider注入替换LayoutManager注入。

@Inject
lateinit var layoutManager: Provider<RecyclerView.LayoutManager>

...

recyclerView.setLayoutManager(layoutManager.get())

1
哇,谢谢,所以每次调用get()时,Provider都会创建一个新的实例...嗯。 - Daniel Wilson
提供程序创建了一个新的 layoutManager 实例。 - NickUnuchek
我得到了错误信息:类Provider不应该有类型参数。 - MML

4

我从 FragmentA 打开了 FragmentB,然后返回到 FragmentA 时出现了异常。我找到了一个错误,是在 onCreate 中创建的:

linearLayoutManager = LinearLayoutManager(requireContext())

并在 onCreateView 中使用:

view.recycler_view.layoutManager = linearLayoutManager

由于从FragmentB返回时,linearLayoutManager没有重新创建,因此RecyclerView使用了旧的linearLayoutManager。因此,我将linearLayoutManager = LinearLayoutManager(requireContext())移动到onCreateView中。


4
我也有同样的问题。我通过将LinearLayoutManager实例设置为null来解决它。
public class MyFragment extends Fragment {
protected LinearLayoutManager mLinearLayoutManager;
...

@Override
public void onDestroy() {
    super.onDestroy();
    if(mLinearLayoutManager != null) // Workaround: android.support.v7.widget.LinearLayoutManager is already attached to a RecyclerView
        mLinearLayoutManager = null;
}

3

在我的情况下,我全局声明了一个LinearLayoutManager,并且尝试将相同实例的LinearLayoutManager附加到多个RecyclerView's上,因此我遇到了这个错误。

解决方案是为每个RecyclerView附加不同的LayoutManager,因为一个LayoutManager只能附加到一个Recyclerview上。


1
我曾经遇到过Dagger2的问题,通过删除作用域注释来解决了它。 我已经在代码中注释了一些作用域,当我删除了这些作用域时,问题得以解决。 希望这对你有帮助。
我删除了@MyScope

0

修复此崩溃的可能选项:

  1. FragmentonViewCreated中创建LayoutManager的实例:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    recyclerView.layoutManager = LinearLayoutManager(context) 
}

如果需要在Fragment中将LayoutManager实例作为变量,则应在onDestroyView中从RecyclerView中分离该实例:
class MyFragment : Fragment() {
    private val myLayoutManager by lazy { LinearLayoutManager(context) }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        recyclerView.layoutManager = myLayoutManager  
    }

    override fun onDestroyView() {
        recyclerView.layoutManager = null
        super.onDestroyView()
    }
}

第二个选项可行,因为抛出异常的条件将为false。以下是RecyclerViewsetLayoutManager方法的代码:
...

if (layout != null) {
    if (layout.mRecyclerView != null) { // will be false
        throw new IllegalArgumentException("LayoutManager " + layout
                + " is already attached to a RecyclerView:"
                + layout.mRecyclerView.exceptionLabel());
    }
    mLayout.setRecyclerView(this);
    if (mIsAttached) {
        mLayout.dispatchAttachedToWindow(this);
    }
}

0
我遇到了Dagger2的这个错误,通过在LinearLayoutManager之前使用Provider就轻松解决了;
 @Inject

 Provider <LinearLayoutManager> linearLayoutManager;

 mViewDataBinding.rvResult.setLayoutManager(linearLayoutManager.get());

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