ListView异步加载网络图片完美版之双缓存技术
问题描述:以前对ListView加载网络图片以及缓存机制进行了分析,本来自以为已经完美了,前段时间有朋友说还有问题,问题是AsyncTask中的线程池满了>128。以前控制线程数量的方法是在ListView处于Fling状态的时候不去启动下载线程,然而这样的做法没有从更本上控制线程的数量。
解决方案:今天我将通过生产者消费者模式+信号量来控制AsynTask的执行。
// 通过信号量控制同时执行的线程数 Semaphore mSemaphore = new Semaphore(50); // 这里是任务的消费者,去任务队列取出下载任务,然后执行,当没有任务的时候消费者就等待 class Executor extends Thread { @Override public void run() { while (true) { ImageLoadTask task = null; try { task = mTasks.take(); if (task != null) { mSemaphore.acquire(); task.execute(); task.cancel(true); } } catch (InterruptedException e) { e.printStackTrace(); } } } } public void loadImage(String url, BaseAdapter adapter, ViewHolder holder) { resetPurgeTimer(); Bitmap bitmap = getBitmapFromCache(url);// 从缓存中读取 if (bitmap == null) { holder.mImageView.setImageResource(R.drawable.ic_launcher);// 缓存没有设为默认图片 ImageLoadTask imageLoadTask = new ImageLoadTask(url, adapter); try { //将任务放入队列中 mTasks.put(imageLoadTask); } catch (InterruptedException e) { e.printStackTrace(); } } else { holder.mImageView.setImageBitmap(bitmap);// 设为缓存图片 } }
@Override protected void onPostExecute(Bitmap result) { mSemaphore.release(); if (result == null) { return; } addImage2Cache(url, result);// 放入缓存 adapter.notifyDataSetChanged();// 触发getView方法执行,这个时候getView实际上会拿到刚刚缓存好的图片 }
总结:我本来还想了一种解决的办法就是,在ViewHold中保留一个AsynTask的引用,如果AsyncTask的状态为Running则将其cancle,但是没有cancle掉,希望知道的朋友解答一下。