通过查看统计平台反馈回来的错误报告,发现在android 4.0系统下,Viewpager屡屡报错。原因与Viewpager中包含有自定义Listview有关,而原生的Listview控件不会报错。Viewpager中存放着四个自定义的Listview(下拉刷新),在切换的过程中就会崩溃,如图:
出错位置在PagerAdapter的destroyItem方法中,会报java.lang.IllegalArgumentException: The observer is null 错误,堆栈信息如下,请仔细看:
java.lang.IllegalArgumentException: The observer is null. at android.database.Observable.unregisterObserver(Observable.java:59) at android.widget.BaseAdapter.unregisterDataSetObserver(BaseAdapter.java:42) at android.widget.HeaderViewListAdapter.unregisterDataSetObserver(HeaderViewListAdapter.java:256) at android.widget.AbsListView.onDetachedFromWindow(AbsListView.java:2309) at android.view.View.dispatchDetachedFromWindow(View.java:8197) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1968) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1966) at android.view.ViewGroup.removeViewInternal(ViewGroup.java:3257) at android.view.ViewGroup.removeViewInternal(ViewGroup.java:3237) at android.view.ViewGroup.removeView(ViewGroup.java:3185) at com.aheudev.a.slickdeals.adapters.DealPageAdapter.destroyItem(DealPageAdapter.java:174) at android.support.v4.view.ViewPager.populate(ViewPager.java:415) at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:696) at android.support.v4.view.ViewPager.computeScroll(ViewPager.java:668) ……………………………… ………………………………
而这些错误来源于我们复写的PagerAdapter中的这个方法:
@Override public void destroyItem(View collection, int position, Object view) { ((ViewPager) collection).removeView((View) view); }
原因是Listview的adapter 中的unregisterDataSetObserver方法被调用了两次,导致observer为空。我们只要复写与Listview绑定的适配器中的unregisterDataSetObserver方法即可,在其中做一个非空判断即可。按如下代码:
@Overridepublic void unregisterDataSetObserver(DataSetObserver observer) { if (observer != null) { super.unregisterDataSetObserver(observer); } }
如上图,比如移动到第三个tab页,会把第一个tab页中的view移除;移动到第四个tab页会把第二个tab页中的view移除掉。当我们再次移动到第三个tab页时,Viewpager依旧会将第一个tab页中的View移除……
有移除就有添加,本来这没有什么。但是通过Log打印的信息,我发现在android 4.0中,Viewpager除了移除View中的列表组件Listview之外,还同时多做了一件事情,那就是调用列表组件Listview的适配器Adapter的unregisterDataSetObserver方法,移除了与适配器绑定数据集观察者DataSetObserver ,也就是那个observer。但是在4.0以下的系统中,ViewPager没有移除列表组件Listview的数据集观察者observer。
所以当再次移动到第三个tab时,会继续卸载位于第一个位置tab中的listview的观察者 ,这时因为观察者已经被卸载为空,而报非法的参数错误。
让人疑惑的就是4.0下:原生的Listview在移除观察者时,没有任何问题。自定义的Listview在移除观察者时,就会报以上的堆栈信息。如果有哪位大虾知道出现这种不兼容原因,欢迎指教。
参考资料:http://stackoverflow.com/questions/7290841/java-lang-illegalargumentexception-the-observer-is-null
原文链接:http://www.67tgb.com/?p=495
欢迎访问:望月听涛