ImageLoader的简单分析(四)

来源:互联网 发布:触发器 sql 编辑:程序博客网 时间:2024/06/05 23:42

之前通过三篇博客从实现原理上对ImageLoader的工作流程做了简单的梳理,本篇就ImageLoader的另外一个小知识点做一些总结—Handler的作用。
在进行正式开始之前先做个引言吧,我们知道在使用AsyncTask的时候可以通过onPostExecute对doInbackground方法执行完成后对UI进行更新,当然我们还知道android的UI更新只能在UI线程中去做,那么AsyncTask的内部是如何从后台线程转到UI线程的呢?
其实很简单内部定义了Handler,我们初始化AsyncTask的时候是在UI线程中初始化的,而AsyncTask在初始化的时候又对Handler进行了初始化:

//在UI线程中对handler进行初始化  private static final InternalHandler sHandler = new InternalHandler();

在AsyncTask执行postResult的时候就是用sHandler发送了消息,并在handleMessage这个方法里面执行了onPostExecute方法,所以就可以确保用户更新UI了!

private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();//发送消息        return result;    }      private static class InternalHandler extends Handler {        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})        @Override        public void handleMessage(Message msg) {            AsyncTaskResult result = (AsyncTaskResult) msg.obj;            switch (msg.what) {                case MESSAGE_POST_RESULT:                    //finish方法里面执行了onPostExecute方法                    result.mTask.finish(result.mData[0]);                    break;                case MESSAGE_POST_PROGRESS:                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }    }

可以看到AsyncTask内部是使用了handler来调用onPostExecute方法来完成更新UI的操作的。那么ImageLoader是不是也如此呢?通过解读DisplayImageOptions源码可以发现该类提供了一个handler引用:

private final Handler handler;private DisplayImageOptions(Builder builder) {    handler = builder.handler;}

可以通过DisplayImageOptions的Builder进行对handler的初始化:

public Builder handler(Handler handler) {            this.handler = handler;            return this;        }

所以我们在构建DisplayImageOptions的时候可以用如下代码来配合默认的handler:

DisplayImageOptions options = new DisplayImageOptions.Builder()                .handler(new Handler()) // default UI Handler                .build();

那么这个handler是如何使用的呢?通过《ImageLoader的简单分析(二)》和《ImageLoader的简单分析(三)》的讲解知道在创建下面两个对象的时候会使用handler:

//显示ImageView图片的taskProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,                        defineHandler(options));//加载并展示ImageView图片的Task                     LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,                    defineHandler(options));

根据上面的代码,让我们看看defineHandler(options)这个方法,该方法位于ImageLoader类中:

private static Handler defineHandler(DisplayImageOptions options) {        Handler handler = options.getHandler();        if (options.isSyncLoading()) {            handler = null;        } else if (handler == null && Looper.myLooper() == Looper.getMainLooper()) {            handler = new Handler();        }        return handler;    }

这个defineHandler方法很明显坐了如下简单的操作:
1)从DisplayImageOptions里面获取用户配置的handler
2)如果ImageLoader使用的是同步方式工作,那么即使配置了handler也会制空
3)如果是异步,并且你没有配置自己的handler同时还是处于UI线程中(调用的displayImage方法),那么ImageLoader就是给你初始化一个handler使用。
(注意:上面括号里特别说明了是在UI线程中调用的displayImage方法,下面会有说明)
那么这个handler最终会在那个地方使用呢?通过前面三篇博客的讲解,事实上是在下面的代码中执行的:

LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);static void runTask(Runnable r, boolean sync, Handler handler, ImageLoaderEngine engine) {        if (sync) {            r.run();        } else if (handler == null) {            engine.fireCallback(r);        } else {            handler.post(r);        }    }

最终是在LoadAndDisplayImageTask的runTask方法中使用handler,runTask方法的任务也很简单:
1)如果ImageLoader是同步处理机制的话,就直接执行相关Runnable的run方法来使得ImageView展示图片(具体讲解参考之前的博客)
2)如果是异步并且handler为null:当你在客户端没有配置handler并且displayImage方法在非UI线程中调用的时候,这个else if分支就会执行(其他执行这分支的情况暂时还没发现,如果读者发现了别的情况,希望留个言点化博主)。此时由于是在非UI线程中调用,所以ImageLoader会给打印如下log提示:

Can't set a drawable into view. You should call ImageLoader on UI thread for it.

3)如果ImageLoader采用了异步工作的方式,并且配置了自己的handler那么,直接让handler来处理相关的Ruannable,最终会执行DisplayBitmapTask的run方法完成ImageView图片的展示(详见《ImageLoader简单分析(二)》《ImageLoader简单分析(三)》两篇博客。
当然至于在使用ImageLoader的过程中,要不要配置handler,是具体情况(比如ImageLoader的同步异步工作方式的选择等情况)而定了。
本文对ImageLoader的handler具体工作的地方做了一些简单的梳理,如有不当的地方或者需要完善的地方,欢迎指正,共同学习!

0 0
原创粉丝点击