在android开发中,为了UI线程能及时响应需要避免在其中执行耗时操作,以防止界面假死甚至ANR。我们一般把耗时操作如下载,查询放在一个单独的线程中。这之后再将结果更新到UI界面。android平台在非UI线程中更新界面大致有以下几种方式:

Activity.runOnUiThread(Runnable)View.post(Runnable)AsyncTask<Params, Progress, Result>Handler.post(Runnable)

其中后面两种方式我们用的比较多,而AsyncTask也是基于Handler进行封装的,可以看出Handler是我们更新UI线程的利器。看下常用的Handler构造方法:

public Handler() {   this(null, false);}public Handler(Callback callback, boolean async) {    .....    mLooper = Looper.myLooper();    .....    mQueue = mLooper.mQueue;    mCallback = callback;    mAsynchronous = async;}

从第二个方法里面可以看出,新建一个handler对象,主要是使其final MessageQueue mQueue作用域指向一个对象,其它的作用域用默认的都行。mQueue来自mLooper = Looper.myLooper();看下myLooper()方法的实现:

public static Looper myLooper() {    return sThreadLocal.get();}// sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

到这里是时候说明下ThreadLocal了,ThreadLocal是java中为每个线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制。这里我们只要记住以下几点:1.每个线程中获得的ThreadLocal的值都是线程独立的,和其它线程没有关联。2.对于ThreadLocal的理解在记住第一点的基础上只需要记住public void set(T)和public T get()两个接口就可以。
事实上android利用ThreadLocal,为每个UI线程建立一个looper对象,每个looper对象有一个消息队列MessageQueue。每次声明一个handler,其主要步骤就是绑定当前线程的消息队列,这之后就可以利用handler将需要的操作派发到消息队列中。一般在每个线程的开始执行Looper.prepare();这是为当前线程创建线程私有的looper对象,这之后就可以声明handler;一般在每个线程的最后执行Looper.loop();前面说明handler绑定了当前线程的消息队列,loop()方法就是监听消息队列,并且执行操作,因此这个方法是一个无限循环,其之后的代码都不会执行,所以在线程的最后执行。
这种模式有点像大学操作系统中的生产者和消费者模式,looper就像消费者,handler就像生产者,比较特殊的是在一个线程中消费者looper只能有一个,生产者handler可以有多个。接下来带着上面的知识看看looper中的主要代码:

public static void prepare() {    prepare(true);}private static void prepare(boolean quitAllowed) {    if (sThreadLocal.get() != null) {        throw new RuntimeException("Only one Looper may be created per thread");    }    sThreadLocal.set(new Looper(quitAllowed));}public static void loop() {    final Looper me = myLooper();    final MessageQueue queue = me.mQueue;    for (;;) {        Message msg = queue.next(); // might block        .....        msg.target.dispatchMessage(msg);    }}

在程序中如果某一个子方法里面涉及到了handler而当前线程没有绑定looper(比如在某个自己新建的线程中新分配的一个对象就可能需要handler),运行时就会抛出异常:

        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }

而如果只在线程的开头执行Looper.prepare();而没有执行Looper.loop();就会出现很多操作不会执行的现象。:)

最后再总结下:用了很久的Handler.post(Runnable),一直没去深入看下原理。android封装的真的很好,涉及到更新UI的东东就上面说的已经够用,如果有一些特殊的需要HandlerThread,AsyncTask都已经帮我们封装好了。不过既然公开了源代码,还是去了解下实现原理比较好。O(∩_∩)O~~

更多相关文章

  1. android sp&wp
  2. Android(安卓)Acrchitecture Components( 架构组件)+热门框架(Re
  3. 你不知道的 Android(安卓)WebView 使用漏洞
  4. Android(安卓)App卡顿慢优化之多线程优化
  5. [Android实例] Android(安卓)开发者面试题-广播机制详解
  6. Only the original thread that created a view hierarchy can t
  7. Android(安卓)Handler 机制
  8. Android的Handler,Looper源码剖析
  9. [置顶] 【Android归纳决】Asynctask与Handler异步综述

随机推荐

  1. Android开发之自动提示框—AutoCompleteT
  2. Android国际化和布局
  3. Android(安卓)修改包名
  4. Android 面试会问到的面试题(持续更新中)
  5. [Android进阶]Android 开发最佳实践
  6. Android事件1-开发指南-用户界面-事件处
  7. android 渠道包自动化测试流程图
  8. 从原生APK反编译,拿到界面,用于mono for
  9. Android城市联动,城市列表展示
  10. android linux 基础知识总结(2)