ImageLoader的简单分析(四)

之前通过三篇博客从实现原理上对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图片的task
ProcessAndDisplayImageTask 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具体工作的地方做了一些简单的梳理,如有不当的地方或者需要完善的地方,欢迎指正,共同学习!

你可能感兴趣的:(ImageLoader的简单分析(四))