Jonathan
Jonathan

Reputation: 3457

ClassCastException cannot convert LinearLayout$LayoutParams to AbsListView$LayoutParams when setting ListView Header

First off, I've already figured out how to solve this bug, but at this point I'm just wondering why my fix works. The situation I was running into was that I was getting a ClassCastException, cannot convert LinearLayout$LayoutParams to AbsListView$LayoutParams when I tried to do the following (simplified for these purposes):

mLayout = (LinearLayout) getLayoutInflater()
   .inflate(R.layout.my_header_layout, 
   getListView(), false);
mRootView.addView(mLayout);
getListView().addHeaderView(mLayout);
getListView().setAdapter(mAdapter);

I eventually broke it down and discovered that the issue was fixed when I removed the call to mRootView.addView(mLayout)

My two-fold question is, why is this happening? First, on the conceptual side, why is it that when a header view is already in the layout the whole thing just dies? Is it because that view is effectively trying to be laid out twice: once for the header and once for the actual layout?

Secondly, why this exception? It seems awfully non-descriptive and it doesn't look like it captures the actual problem at all? Is this a case of a high level issue not being handled because a lower level function will just fail on the results anyway?

Upvotes: 4

Views: 1392

Answers (2)

Geobits
Geobits

Reputation: 22342

My question is, why is this happening? First, on the conceptual side, why is it that when a header view is already in the layout the whole thing just dies? Is it because that view is effectively trying to be laid out twice: once for the header and once for the actual layout?

Your layout params are going crazy here, that's the problem.

  • inflate() is called, assigning ListView.LayoutParams to mLayout, since you pass a ListView as the root. From the docs:

root: Optional view to be the parent of the generated hierarchy (if attachToRoot is true), or else simply an object that provides a set of LayoutParams values for root of the returned hierarchy (if attachToRoot is false.)

  • When you use addView(), it checks the type of the child's params. If it doesn't match, it converts it as best it can. It does this by copying the values over in a new constructor. So, your mLayout now has LinearLayout.LayoutParams attached.

  • Once you call addHeaderView(), mLayout is now a child of the listview. One of the things done during ListView#setupChild() is this:

    AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();

This is almost definitely where you're getting the ClassCastException. You just can't do a straight cast like that.


Secondly, why this exception? It seems awfully non-descriptive and it doesn't look like it captures the actual problem at all?

It's not that bad, but you have to understand how the layout system works. Could they do a simple check, and just throw an error or log message if it's not right? Sure. Could ListView try to gracefully handle the issue the way a LinearLayout does? Sure. But they don't.

It might be worth posting on the Android Developer's forum/group/tracker if you think it could be handled better.

Upvotes: 4

Jeeter
Jeeter

Reputation: 6085

It all lies in the statement:

cannot convert LinearLayout$LayoutParams to AbsListView$LayoutParams

LinearLayout and AbsoluteListView have 2 different types of layouts, so you would need to setup the LayoutParams by using the following:

mLayout.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

because now you are using AbsListView-specific LayoutParams.

Upvotes: 0

Related Questions