Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: ID clash when 3 tabs or more are created

I have a tabbed view in Android, and the tabs share the same xml layout, they are dynamically generated based on JSON. For example, if I have one Menu, it will create one tab. Two menus, two tabs. And so on. As all the tabs are based on the same "Menu" object, they share the same xml being inflated.

The construction of the tabs goes without problems. When have one or two tabs, changing states and swiping is done flawlessly. When having three or more tabs, swiping to right is working, but whenever I swipe back to left, I get this error:

java.lang.IllegalArgumentException: Wrong state class, expecting View State but received class android.widget.AbsListView$SavedState instead. This usually happens when two views of different type have the same id in the same hierarchy. This view's id is id/header_list_view. Make sure other views do not use the same id.

Here is my onCreateView code:

public class MenuToListFragment extends Fragment {

HeaderListView headerListView;

// (most of the logic removed)

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

    View rootView = inflater.inflate(R.layout.fragment_menu, container, false);
    headerListView = (HeaderListView) rootView.findViewById(R.id.header_list_view);
    return rootView;
}
}

And here is my xml layout:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="<removed>.DisplayMenus">


    <com.applidium.headerlistview.HeaderListView
        android:id="@+id/header_list_view"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />

</LinearLayout>

Thanks for your help!

like image 644
Stephane Maarek Avatar asked Jan 11 '23 00:01

Stephane Maarek


2 Answers

Alright, found the bug! Using method OnActivityCreated, when calling the HeaderListView, I had to assign an unique Id using headerListView.setId(); For the value of this id, I had to pass the position of the tab by a bundle, using setArguments and getArguments. One way I haven't explored yet is to generate an Id using headerListView.setId(headerListView.generateViewId()).

Now, about the "why" it happened only when having 3 view or more. This is where I'm guessing and I'd love some feedback. When inflating a tab, I found that only the neighbors were kept in memory (the other are somehow dropped?). If two tabs, going left or right won't have the program generate or restore views as the set (neighbor-in use tab) is always the same. Now, if I have 3 tabs and swiping all the way to the right, the first tab gets puts to sleep. Swiping back to the second tab forces android to restore the first tab from its sleep state. Because the sleeped tab had the same id as all others, it would generate a conflict. Voila!

Hope this helps people encountering the same issue

like image 184
Stephane Maarek Avatar answered Jan 19 '23 02:01

Stephane Maarek


I changed layout definition in:

<com.applidium.headerlistview.HeaderListView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:tag="HeaderListView" />

and then find view using tag:

mHeaderListView = (HeaderListView) view.findViewWithTag("HeaderListView"); 

It seems to work, no more java.lang.IllegalArgumentException.

like image 27
Burt Avatar answered Jan 19 '23 01:01

Burt