6.4 列表相关的异常
有Adapter在的地方,就有ListView,就有因此而产生的异常。这些异常基本是因为下拉列表刷新数据时处理不当导致的。这主要是Android本身没有提供标准的下拉刷新数据的列表控件,而网上千奇百怪的下拉刷新控件又都有这样那样的缺陷。封装得再完善的下拉列表控件,也只能确保在大部分机型上工作良好。
6.4.1 Adapter数据源变化但是没通知ListView
异常中的关键字:
The content of the adapter has changed but ListView did not receive a notification.Make sure the content of your adapter is not modified from a background thread,but only from the UI thread.
发生频率:★★★★★
上述异常信息的大体意思是,adapter的内容变化了,但是相应的ListView并不知情。请保证adapter的数据在主线程中进行更改!
首先,一种极端的解决方案是,每次设置adapter中的集合数据时,都要将其clone一份,而不是直接传递一个集合过来。但是这样会比较消耗性能。
其次,要确保每次在Activity中设置adapter的值,而不是在后台线程,有以下几个办法:
1)调用Activity的runOnUiThread()方法,如下所示:
private class OnClickListenerImpl implements View.OnClickListener { @Override public void onClick(View arg0){ new Thread(){ public void run(){ MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { textView1.setText("Hello World!"); } }); } }.start(); } }
2)调用Handler,通知主线程修改adapter。
3)使用AsyncTask也是一个不错的选择,虽然它也有很多缺陷。
最后,无论何时何地,只要修改了adapter中集合数据的值(比如设置一个集合数据、加一笔数据、清空集合数据),就要马上调用notifyDataSetChanged方法,以确保列表同步更新。
这个异常在Android技术圈儿里可算是大名鼎鼎了,基本上所有的App应用都存在这样的崩溃。
6.4.2 ListView滚动时点击刷新按钮后崩溃
异常中的关键字:
java.lang.IndexOutOfBoundsException:Invalid index 30,size is 1 at
java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)at
java.util.ArrayList.get(ArrayList.java:304)at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:225)
发生频率:★★★
Listview滚动的时候,表示它已经获取了adapter的getCounts(),可能是30,也可能更大。回调用getView(),这个时候将数据clear掉了。当然会报IndexOutOfBoundsException:Invalid index 30,size is 1。这个1是那个header,因为我们使用的是HeaderViewList Adapter。
这种Crash的解决方案是,Listview滚动的时候,将刷新按钮设置为不可点击,如下所示:
public void refresh() { startLocation(); pageNo = 0; hasMore = true; dataList.clear(); moreBtn.setVisibility(View.GONE); loadFirstPageData(); }
6.4.3 AbsListView的obtainView返回空指针
异常中的关键字:
java.lang.NullPointerException at android.widget.AbsListView.obtain View(AbsListView.java:1521)at android.widget.ListView.makeAndAddView
发生频率:★★★
导致空指针的罪魁祸首是AbsListView的obtainView方法获取不到View,究其原因是getView方法在某些时候返回null。
解决方案很简单,getView的第二个参数convertView是不会为null的,在getView返回值的时候,判断一下是否为null,如果为null,则返回convertView。
6.4.4 Adapter数据源变化但是没调用notifyDataSetChanged
异常中的关键字:
The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged
发生频率:★★
PagerAdapter对于notifyDataSetChanged()和getCount()的执行顺序是非常严格的,系统跟踪count的值,如果这个值和getCount返回的值不一致,就会抛出这个异常。所以为了保证getCount总是返回一个正确的值,那么在初始化ViewPager时,应先给adapter初始化内容后再将该adapter传给ViewPager,如果不这样处理,在更新adapter的内容后,应该调用一下Adapter的notifyDataSetChanged方法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论