浏览 10038 次
锁定老帖子 主题:ListView异步加载网络图片之三
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-10-07
ListView异步加载网络图片之完美解决方案
问题描述:上一篇文章中解决了一个图片显示混乱的bug,但是还遗留下来一个更严重的bug,那就是当我们猛地拖动列表的时候,会感觉非常的卡顿,并且继续不顾一切的拖动程序就会崩溃,看一下抛出的异常是RejectedExecutionException。 错误的原因:由于异步加载图片用的是AsyncTask(异步任务),AsyncTask的内容实现是采用的一个线程池,池子的的最大容量是128,然而连续的滚动ListView触发了getView的调用,在getView中又去创建并执行了异步任务,所以就会导致线程池满了,看一下AsyncTask的源码 //池子的最大容量 private static final int MAXIMUM_POOL_SIZE = 128; //池子 private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory); 从AysncTask的execute方法中调用线程数的方法sExecutor.execute(mFuture),下面就是线程池的execute方法,在这个方法中由于线程池满了,所以命名会被拒绝执行也就会调用reject(command) 最终将会抛出RejectedExecutionException异常。 public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); } 追踪到抛出异常的代码是在AbortPolicy类,AbortPolicy实现了RejectedExecutionHandler接口因此实现了rejectedExecution方法 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { // BEGIN android-changed // provide diagnostic messaging for a common exception // a message is helpful even if it isn't created atomically int queueSize = e.getQueue().size(); int remainingCapacity = e.getQueue().remainingCapacity(); String message = "pool=" + e.getPoolSize() + "/" + e.maximumPoolSize + ", queue=" + queueSize; if (remainingCapacity != Integer.MAX_VALUE) { message += "/" + (queueSize + remainingCapacity); } throw new RejectedExecutionException(message); // END android-changed } 解决的方法:产生问题的原因是执行了太多的异步任务,所以解决问题的方法就是,减少异步任务的创建,那么如何减少呢?我们知道ListView在的滚动有3个状态
那么可以在adapter中通过一个变量mBusy来控制adapter的状态当mBusy==false的时候才去创建异步任务,并且我们给ListView设置一个setOnScrollListener,在监听器的回调函数中改变adapte的mBusy的值,达到控制是否创建异步任务的作用 OnScrollListener mScrollListener = new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { case OnScrollListener.SCROLL_STATE_FLING: adapter.setFlagBusy(true); break; case OnScrollListener.SCROLL_STATE_IDLE: adapter.setFlagBusy(false); break; case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: adapter.setFlagBusy(false); break; default: break; } adapter.notifyDataSetChanged(); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }; @Override public View getView(int position, View convertView, ViewGroup parent) { Log.d(TAG, "position=" + position + ",convertView=" + convertView); ViewHolder viewHolder = null; if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate( R.layout.list_item, null);// 这个过程相当耗时间 viewHolder = new ViewHolder(); viewHolder.mTextView = (TextView) convertView .findViewById(R.id.tv_tips); viewHolder.mImageView = (ImageView) convertView .findViewById(R.id.iv_image); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } String url = ""; url = URLS[position % URLS.length]; if (!mBusy) { mImageLoader.loadImage(url, this, viewHolder); viewHolder.mTextView.setText("--" + position + "--IDLE ||TOUCH_SCROLL"); } else { Bitmap bitmap = mImageLoader.getBitmapFromCache(url); if (bitmap != null) { viewHolder.mImageView.setImageBitmap(bitmap); } else { viewHolder.mImageView.setImageResource(R.drawable.ic_launcher); } viewHolder.mTextView.setText("--" + position + "--FLING"); } return convertView; } 总结:本文对前一个demo遗留的bug做了讲解并解决,在此基础上还对程序做了进一步的优化,这次的demo通过双缓冲技术对数据进行缓存,代码已经上传,同学们可以自己下载下来研究一下双缓冲技术。我在下一篇博客中会对双缓冲的代码进行详细的分析,谢谢您看到了博客的结尾。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-10-09
滑动的时候也最好不要异步加载
|
|
返回顶楼 | |
发表时间:2012-10-10
clarkhuang 写道 滑动的时候也最好不要异步加载
在下一篇文章中已经这样做了,只有ListView是idle的时候才异步请求的嘿嘿,我写博客是循序渐进的,卖关子了 |
|
返回顶楼 | |
发表时间:2012-12-25
下篇文章的链接应该给一下
|
|
返回顶楼 | |
发表时间:2012-12-26
楼主,下一篇博客的链接地址请给一下!谢谢
|
|
返回顶楼 | |
发表时间:2012-12-29
xzch 写道 楼主,下一篇博客的链接地址请给一下!谢谢
你看看这个:http://heisedeyueya.iteye.com/blog/1757010 |
|
返回顶楼 | |