Android Listview addHeaderView 引起的Crash
Crash信息如下:
java.lang.IllegalStateException:
Cannot add header view to list -- setAdapter has already been called.
android.widget.ListView.addHeaderView(ListView.java:258)
android.widget.ListView.addHeaderView(ListView.java:287)
应用场景:
页面展示列表信息,但是在列表为空的时候需要展示一个EmptyView,所以在列表加载或刷新的时候,如果数据为空,在把EmptyView通过listview的addHeaderView添加到列表中,列表有刷新功能,所以会频繁的调用removeHeaderView 和 addHeaderView,但是在低版本的Android手机中会出现如下崩溃信息。
引起原因:
Android不同版本中,代码实现也会有很大变化。Android4.3中Listview的addHeaderView代码如下:
public void addHeaderView(View v, Object data, boolean isSelectable) {
if (mAdapter != null && ! (mAdapter instanceof HeaderViewListAdapter)) {
throw new IllegalStateException(
"Cannot add header view to list -- setAdapter has already been called.");
}
....
}
Crash就是在这里产生的,当listview频繁进行addHeaderView 和removeHeaderView时,当listview已经设置了Adpater后,调用addHeaderView就会出现该异常信息,Android4.3及低版本中就会出现。
解决方法:
采用了一种比较安全和高效的方法,主要思路是先把EmptyView通过addHeaderView 添加到listview (setAdapter之前),后面通过设置特殊View的可见性来控制是否显示。
这里还有一个小问题要说一下,按照这种方式添加的listview中,添加的特殊View即使隐藏掉了,但是ListView的最上面也会出现一个空白区域 ,网上很多都说通过设置EmptyView的setPadding(0,0,viewheight,0)来隐藏和显示,但是这种做法不太好操作,我采用的方法是,特殊View的最外层包裹一个layout,隐藏式将内部的View隐藏即可。例如,下面这个布局文件,添加到listview中,只需要设置layout_container不可见即可,就不会出现listview顶部的空白区域。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/layout_view"
android:orientation="vertical">
<LinearLayout
android:id="@+id/layout_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#9DB16D"
android:textSize="40sp"
android:text="TextView" />
</LinearLayout>
</LinearLayout>