高效的加载图片2.通过子线程(AsyncTask)加载图片

来源:互联网 发布:开淘宝网店如何找货源 编辑:程序博客网 时间:2024/04/29 19:07

上一篇我们说到如何以较小的内存,打开较大的图片中使用了
BitmapFactory.decodeResource(res, resId, options);我们再主线程中执行了该方法,测试显示没有任何问题。我们的图片资源是来自本地的文件,可是,如果我们的图片来自sd卡甚至是来自网络的资源,再在UI线程中使用该方法,那么是很容易引起线程阻塞,导致ANR异常的(Application Not Responding)。
避免这个问题的解决方案,就是将图片的加载过程放到子线程中执行,直到图片加载完后,再通知主线程,让主线程显示这个图片。
这篇文章就是教你如何在AsyncTask中,后台加载图片,并且处理并发的问题。
我们先说一下AsyncTask这个类。
这个类是安卓最简单的调用子线程,在后台完成任务,并且将结果返回到主线程的类。

AsyncTask<Integer, Void, Bitmap>

如何开始这个任务:new AsyncTask.execute(params);
在后台执行的方法:doInBackground(Integer… params);
后台方法执行完成后在主线程中执行的方法:onPostExecute(Bitmap bitmap)
要能够很好的运用这个类,需要知道Integer, Void, Bitmap这三个参数分别的作用。如果你只是简单的需要在后台完成某项任务,无需任何UI操作,那三个参数都可以是void。
第一个参数是指定的输入的类型,即在执行execute()方法时所输入的参数,可以是一个或多个。这个参数会在doInBackground(Integer… params);中接收到。这里面指定的是Integer类型。
第二个参数可指定发送进度更新需要的类型,这个参数会在onProgressUpdate(Void… values);中接收,在这个方法里一般都是写设置进度条进度的代码。
它的工作方式如下:
在后台线程中,我们从doInBackground()方法中调用publishProgress()方法。这样onProgressUpdate()方法就能在UI线程上被调用。因此我们就可以在onProgressUpdate()方法中执行UI更新,但我们必须在doInBackground()方法中使用publishProgress()方法对它们进行控制。
第三个参数是指定返回值类型的。在doInBackground()方法中需要return一个值,在onPostExecute(Bitmap bitmap)方法中获得的参数bitmap就是doInBackground()返回的值。而第三个参数就是指定这个值的类型的。

在某项复杂的场景中,我们需要能够随时能够撤销运行中的AsyncTask。比如ListView加载图片时,当执行某个图片加载任务时,要显示的ImageView控件已经不见了,那当然不需要再执行这个任务了。于是我们就可以调用AsyncTask.cancel(boolean)方法。
撤销AsyncTask任务有两种模式,粗暴的和温和的。如调用温和的.cancel(false),该方法会设置isCancelled()的状态为true。随后AsyncTask会检查doInBackground()方法中的isCancelled()的状态,然后选择提前终止任务。
然而,如调用.cancel(true),它会直接终止doInBackground()方法所在的线程。如果可能,应该尽量避免使用此种方式。

http://blog.csdn.net/androidzhaoxiaogang/article/details/8579095
这篇博客是按照安卓开发文档翻译的,我实力有限,就不班门弄斧了。等看懂后再修改这篇博客。
http://m.blog.csdn.net/blog/domyself918/24260133
这篇博客也是安卓开发文档的翻译,但比较详细。
http://blog.csdn.net/matrix_xu/article/details/8424038
这篇博客是讲弱引用的用法和作用的,我觉的写的很好。一起分享了。

2015/10/13
并发问题,有可能导致一个View同时加载两多个图片,并且因为不能确定完成的先后顺序,很有可能导致图片加载错误。
看上面推荐的第二个博客后,觉的有所收获,所以把收获写下来。
针对的主要是并发性问题的处理。当使用listView或GirdView这中循环使用view来加载图片时。因为无法确定加载图片所用的时间,
1.可能在想要加载某个view的图片时,这个view正在加载图片了(因为一个view的循环使用会导致它可能多次加载)。这时候需要取消正在加载的任务,而是让新的任务开始加载。

public static boolean cancelPotentialWork(int data, ImageView imageView) {//先获得ImageView的正在加载,或者是已经加载了的task    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);    if (bitmapWorkerTask != null) {    //不为null说明imageView正在加载,或是已经加载了一个task    //获得这个ImageView的ID        final int bitmapData = bitmapWorkerTask.data;        // 如果bitmap还没有被设置或者bitmapdata数据和正在执行的data的不一样        if (bitmapData == 0 || bitmapData != data) {            // 那么就把之前的task取消掉            bitmapWorkerTask.cancel(true);        } else {            //如果一样那么就是说当前的task就是image的task 就无需重新绑定了            return false;        }    }    // No task associated with the ImageView, or an existing task was cancelled    return true;}

2.还有一种情况是,当想要加载某个View时,发现这个view已经把视图加载完了,这时候要判断这个已经加载的图片是不是自己想要加载的,如果是,则不用加载了,如果不是,应该重新加载图片。
3.当然最后一种情况,当想要加载时,发现没有任务在加载,view上也没有加载图片,所以正常加载就行了。

0 0
原创粉丝点击