Theo Kallioras
Theo Kallioras

Reputation: 3677

"LayoutManager is already attached to a RecyclerView" error

I am trying to have multiple RecyclerViews in a layout but I get the following error: "LayoutManager is already attached to a RecyclerView"

The Java code is:

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

The XML layout code is:

<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>

The MyLinearLayoutManager is a custom LinearLayoutManager I found online in order to solve the wrap-content issue of the SDK LinearLayoutManager.

Is there any way I can have multiple RecyclerViews in a single layout? It seems that I cannot attach more than one LayoutManagers per layout.

Any assistance would be very welcome :)

Upvotes: 53

Views: 22817

Answers (9)

akhbulatov
akhbulatov

Reputation: 1

Possible options to fix this crash:

  1. Create an instance of LayoutManager in onViewCreated of Fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    recyclerView.layoutManager = LinearLayoutManager(context) 
}
  1. If it is necessary to have an instance of LayoutManager as a variable in Fragment, then detach the instance from RecyclerView in onDestroyView:
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()
    }
}

The second option will work, because the condition for throwing an exception will be false. Here is the code from the method setLayoutManager of RecyclerView:

...

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

Upvotes: 0

CoolMind
CoolMind

Reputation: 28799

I opened FragmentB from FragmentA. Then returned back to FragmentA and got this exception. I found an error. I created in onCreate:

linearLayoutManager = LinearLayoutManager(requireContext())

and used in it onCreateView:

view.recycler_view.layoutManager = linearLayoutManager

Because linearLayoutManager hadn't recreated when we returned from FragmentB, RecyclerView used an old linearLayoutManager. So, I moved linearLayoutManager = LinearLayoutManager(requireContext()) to onCreateView.

Upvotes: 4

Farzad Emadi
Farzad Emadi

Reputation: 11

I had this problem with Dagger2 and it was solved by removing the Scope Annotation. I had annotated the code with some scope and when i removed the scope the problem was fixed. I hope this would be helpful to you.

@MyScope @Provides static LinearLayoutManager provideLinearLayoutManager

I deleted the @MyScope.

Upvotes: 1

Arun Prajapati
Arun Prajapati

Reputation: 281

This error I faced with Daggar2 and simply remove by using Provider before the LinearLayoutManager like;

 @Inject

 Provider <LinearLayoutManager> linearLayoutManager;

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

Upvotes: 0

nimi0112
nimi0112

Reputation: 2135

In my case, I had declared a LinearLayoutManager globally and I was trying to attach the same instance of LinearLayoutManager to multiple RecyclerView's so I was getting this error.

The Solution is to attach different LayoutManager to each RecyclerView because one LayoutManager can only be attached to one Recyclerview.

Upvotes: 3

Mikhail Sharin
Mikhail Sharin

Reputation: 4065

I faced this error when providing LayoutManager via Dagger.
The solution is to replace layout manager injection with layout manager javax.inject.Provider injection.

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

...

recyclerView.setLayoutManager(layoutManager.get())

Upvotes: 9

Victor Ruiz.
Victor Ruiz.

Reputation: 1732

Just need to create a new instance:

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

Upvotes: 9

yinsweet
yinsweet

Reputation: 2851

I have the same problem as well. I work around it by setting null to LinearLayoutManager instance.

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

Upvotes: 4

WilliamK
WilliamK

Reputation: 1772

I had this problem too. My Activity uses Tabs, with three fragments, when I go to third tab, and back to first (or second), this error is thrown.

After searching a lot, I found out that may be the garbage collector, because I was using a strong reference.

Since the constructor LinearLayoutManager uses the activity as the parameter (not the fragment), a Tabs Activity stays active during tabs changes.

Removing the local field in mLinearLayoutManager from the class, and using a weak reference, I could get rid of this problem:

before:

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

I changed to:

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

Upvotes: 100

Related Questions