ClassCastException when calling ListView.addHeaderView()?
Asked Answered
C

4

54

I have a fairly complex layout (containing RelativeLayouts, TextViews and ImageViews) that I want to place above a listview. This view should scroll with the listview.

I tried adding the layout as a header to the listview using this code:

View v = inflater.inflate(R.layout.list_view, container, false);

View header = inflater.inflate(R.layout.header_layout, container, false);

// populate views in the header

mList = (ListView)v.findViewById(R.id.list);
mList.addHeaderView(header);
mAdapter = new ReviewsAdapter(getActivity());
mList.setAdapter(mAdapter); <-- error occurs here

ReviewsAdapter is a custom adapter I've written which extends BaseAdapter.

Upon executing the code, I get this error:

11-25 17:19:14.802: E/AndroidRuntime(1215): java.lang.ClassCastException: android.widget.FrameLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams
11-25 17:19:14.802: E/AndroidRuntime(1215):     at android.widget.ListView.clearRecycledState(ListView.java:513)
11-25 17:19:14.802: E/AndroidRuntime(1215):     at android.widget.ListView.resetList(ListView.java:499)
11-25 17:19:14.802: E/AndroidRuntime(1215):     at android.widget.ListView.setAdapter(ListView.java:442)
11-25 17:19:14.802: E/AndroidRuntime(1215):     at com.coppi.storefront.product.ProductReviewsFragment.onCreateView(ProductReviewsFragment.java:104)

If I comment out the mList.addHeaderView(header) line I do not get the error. I can also display the header layout without the listview with no problems.

I'm assuming this has something to do with the contents of the header layout but I'm not sure exactly what would be causing it.

Here is the header xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <RelativeLayout
            android:id="@+id/header_section"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/margin_sides"
            android:background="@color/pdp_availability_section_background" >

            <TextView
                android:id="@+id/header_text"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/margin_sides"
                android:paddingBottom="@dimen/margin_sides"
                android:text="@string/ratings_reviews"
                android:textColor="#000"
                android:textSize="18dp" />
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/body_section"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_below="@id/header_section" >

            <TextView
                android:id="@+id/product_title"
                style="@style/ProductTitleFont"
                android:layout_marginBottom="@dimen/product_title_bottom_margin"
                android:layout_marginLeft="@dimen/margin_sides"
                android:layout_marginRight="@dimen/margin_sides" />

            <RelativeLayout
                android:id="@+id/attributes_section"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/product_title"
                android:layout_centerHorizontal="true"
                android:layout_margin="@dimen/margin_sides" >

                <LinearLayout
                    android:id="@+id/overall_section"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:gravity="bottom" >

                    <TextView
                        android:id="@+id/overall_label"
                        style="@style/ProductTitleFont"
                        android:layout_width="wrap_content"
                        android:text="@string/overall_rating" />

                    <ImageView
                        android:id="@+id/overall_1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="10dp"
                        android:src="@drawable/icon_rating_empty" />

                    <ImageView
                        android:id="@+id/overall_2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/icon_rating_empty" />

                    <ImageView
                        android:id="@+id/overall_3"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/icon_rating_empty" />

                    <ImageView
                        android:id="@+id/overall_4"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/icon_rating_empty" />

                    <ImageView
                        android:id="@+id/overall_5"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/icon_rating_empty" />

                    <TextView
                        android:id="@+id/overall_score"
                        style="@style/ProductTitleFont"
                        android:layout_width="wrap_content"
                        android:layout_marginLeft="10dp"
                        android:text="4.6" />
                </LinearLayout>

                <Button
                    android:id="@+id/rate_review_button"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/overall_section"
                    android:layout_marginBottom="@dimen/margin_sides"
                    android:layout_marginTop="@dimen/margin_sides"
                    android:text="@string/rate_review_button_text" />
            </RelativeLayout>

            <View
                android:id="@+id/attributes_divider"
                android:layout_width="fill_parent"
                android:layout_height="1dp"
                android:layout_below="@id/attributes_section"
                android:layout_marginBottom="@dimen/margin_sides"
                android:layout_marginTop="@dimen/margin_sides"
                android:background="@color/pdp_section_divider" />

            <TextView
                android:id="@+id/review_count"
                style="@style/ProductTitleFont"
                android:layout_width="wrap_content"
                android:layout_below="@id/attributes_divider"
                android:layout_marginLeft="@dimen/margin_sides"
                android:text="0 " />

            <TextView
                style="@style/ProductTitleFont"
                android:layout_width="wrap_content"
                android:layout_alignBaseline="@id/review_count"
                android:layout_marginRight="@dimen/margin_sides"
                android:layout_toRightOf="@id/review_count"
                android:text="@string/customer_reviews" />

            <View
                android:id="@+id/review_count_divider"
                android:layout_width="fill_parent"
                android:layout_height="1dp"
                android:layout_below="@id/review_count"
                android:layout_marginBottom="@dimen/margin_sides"
                android:layout_marginTop="@dimen/margin_sides"
                android:background="@color/pdp_section_divider" />
        </RelativeLayout>
    </RelativeLayout>

Update: I tried reducing the header .xml file to just a single TextView and the problem continues. So I don't believe the problem is being cause by something in the xml.

Contractor answered 26/11, 2011 at 1:38 Comment(2)
Shouldn't that be mList.addHeaderView(header) or is there an actual 'h' view somewhere?Kiyohara
Thanks for catching that, it happened while I was copying the code over. Updated the post to be more accurate.Contractor
B
75

FrameLayout and AbsListView convert their children layout params to FrameLayout.LayoutParams and AbsListView.LayoutParams. This is where the casting fails.

View header = View.inflate(this, R.layout.header_layout, null);

should fix it.

Edit: As mentioned in the comments, changing the ViewGroup Parameter of the inflate call also makes it work:

header = inflater.inflate(R.layout.header_layout, null, false);
Burin answered 26/11, 2011 at 3:48 Comment(9)
Ok... but I'm not using any FrameLayouts. That's why I'm confused. What is it trying to cast?Contractor
Can you try View header = View.inflate(this, R.layout.header_layout.null); ?Burin
Oh, and also: mList = (ListView) findViewById(R.id.list); ?Burin
Changing to View header = View.inflate(this, R.layout.header_layout, null); solved it! Can you explain to me what was happening? Also, edit your answer with this so I can accept it.Contractor
Could you paste the inflater and the container code? Maybe we can have a better look.Burin
This is happening in the onCreateView() method of a fragment. So the inflater and container come from the method parameters. It turns out simply changing the original inflater.inflate(...) call to use null for the ViewGroup parameter also solves the problem.Contractor
So, my guess is that the inflater returned the "wrong" layouts. I'm still a beginner in Android programming, so I'm not 100% sure what could have caused this. Anyway, I'm glad you solved it. And by the way I edited my original answer. Thanks!Burin
+ for the null thing, had thought that it's the causeFrazil
@Souvlaki how can define a onClick listner on header items. I can not do any thing with them?Divergent
C
17

Although Souvlaki's method will fix the issue and allow you to continue working. It is always best to give the view being inflated a reference to the container it will be in. This allows for Android to correctly inflate it for the right context.

What you should do is find the ListView and then pass that to the inflate.

ListView listView = (ListView) layout.findViewById(R.id.listview);
View header = inflater.inflate(this, R.layout.header_layout, listView, false);
Cracy answered 3/10, 2013 at 1:52 Comment(3)
There isn't any method View.inflate which takes 4 arguments.Hirundine
Excellent point. Sorry I should have been using the inflater to make the call not ViewCracy
To be more complete: ListView lv = (ListView) v.findViewById(android.R.id.list); View header = (View) inflater.inflate(R.layout.header_layout, lv, false);Lachance
M
2

I see same situation. in my case, it's a trouble that call timing for ListView.addHeaderView().

Before: (Error)
ListView.addHeaderView() is called in Fragment.onCreateView() method.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View layout = inflater.inflate(R.layout.fragment_main, container, false);
    mListView = (ListView) layout.findViewById(R.id.listview);
    mListView.addHeaderView(inflater.inflate(R.layout.list_header_book, listview, false));
    return layout;
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    mAdapter = new BookAdapter(getActivity(), mBookList);
    mListView.setOnItemClickListener(mBookItemClickListener);
    mListView.setAdapter(mAdapter);
}


After:(OK)
ListView.addHeaderView() is called in Fragment.onActivityCreated() method.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_main, container, false);
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    mAdapter = new BookAdapter(getActivity(), mBookList);
    mListView = (ListView) getView().findViewById(R.id.listview);
    mListView.setOnItemClickListener(mBookItemClickListener);
    mListView.addHeaderView(LayoutInflater.from(getActivity()).inflate(R.layout.list_header_book, null));
    mListView.setAdapter(mAdapter);
}
Monarski answered 7/1, 2015 at 7:46 Comment(1)
This is the only solution that worked for me. Using onActivityCreated.Genni
F
1

From drspaceboo's post above, this worked for me:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    mListLayoutView = inflater.inflate(getLayoutId(), container, false);

    int headerLayoutId = R.layout.list_header_layout;
    mListHeaderView = inflater.inflate(headerLayoutId, mResourcesListView, false);

    // ...

    mResourcesListView.addHeaderView(mListHeaderView, null, false);

Where getLayoutId() returns the main layout that contains the ListView xml

Fidler answered 23/5, 2014 at 23:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.