站在线程角度看Android Handler 机制

来源:互联网 发布:几个淘宝号刷一天挣40 编辑:程序博客网 时间:2024/05/16 06:55

        Android开发的小伙伴们对Handler机制应该非常熟悉了,Handler机制主要用于完成两个线程间互相通信,最典型的应用就是在子线程中执行一系列任务,然后通知UI线程更新UI。主要与Handler 、 Looper 、Message 这三个类相关,其中Handler负责处理(发送,接收并处理)消息,Looper负责维护一个消息队列,并通过一个不断的循环从队列里取出消息交给Handler处理,Message就是消息本身。看过不少文章,作为菜鸟的我心中还是有一些疑问,终于抽时间好好梳理了一下,不多说,直接上问题。

        为了方便描述,我们把UI线程成为主线程,把其他我们自己创建的线程,称为子线程。

        问题一:Handler机制中如何将两个线程联系起来,站在线程的角度,各个线程都做了些啥,执行了哪些语句?

        问题二:UI线程需要处理很多事务且不能堵塞,一个线程只有一个控制权,一个线程中sendMessage之后,处理线程的控制权会在什么时机处理发送过来的message

        问题三:与UI线程绑定的Handler的postDelay(Runnable r, Long delay)方法什么情况下会阻塞UI线程?为啥?   

        从问题一开始,先看一个典型的场景:子线程执行了handler.sendMessage(1),结果是主线程执行了handleMessage方法里的textView.setText();

public class MainActivity extends Activity {      private TextView textView;      private Handler handler = new Handler(){          public void handleMessage(android.os.Message msg) {              textView.setText("Handler");          };      };            @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          textView =(TextView) findViewById(R.id.textView);          new Thread(){              public void run() {//这里是子线程在执行                  try {                      Thread.sleep(1000);                      handler.sendEmptyMessage(1); //                 } catch (InterruptedException e) {                      // TODO Auto-generated catch block                      e.printStackTrace();                  }                };          }.start();      }   }  

         很多文章介绍过,handler的send相关方法和post相关方法最终都会到sendMessageAtTime(Message msg, long uptimeMillis)。我们这里重点关注线程的执行步骤,或者说线程控制权的一步一步转移,看我们handler.sendMessage(1)之后的调用链:

public final boolean sendMessage(Message msg) {        return sendMessageDelayed(msg, 0);    }public final boolean sendMessageDelayed(Message msg, long delayMillis) {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }public boolean sendMessageAtTime(Message msg, long uptimeMillis) {        MessageQueue queue = mQueue;        if (queue == null) {            RuntimeException e = new RuntimeException(                    this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);            return false;        }        return enqueueMessage(queue, msg, uptimeMillis);    }private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;//记住这个target,this就是Handler的一个对象了。。。        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

         子线程执行了handler.sendMessage(1),所以以上调用都是子线程来执行的。在最后一个方法enqueueMessage()中,msg的target指向当前的Handler对象handler。

         所以,例子中的子线程的控制权在以下方法中转移:sendMessage(Message msg)

                                                                                      --->sendMessageDelayed(Message msg, long delayMillis)

                                                                                      --->sendMessageAtTime(Message msg, long uptimeMillis)

                                                                                      --->enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)

                                                                                      --->enqueueMessage() // 这个enqueueMessage是MessageQueue的方法。

         所以子线程就是往handler相关联的MessageQueue里丢了一条Message,然后控制权会回到该线程的run()方法里,去执行handler.sendMessage(1)的下一条语句,在我们的例子里,run()方法执行完毕。子线程进入死亡状态,线程对象等待被回收。

        在Handler机制中,Looper负责从MessageQueue中取出message并做相应处理。子线程既然往handler对应的MessageQueue里丢了一条Message,那肯定这MessageQueue对应的线程和对应的Looper在处理这条message。在sendMessageAtTime(Message msg, long uptimeMillis)方法中,看到所操作的消息队列mQueue,看一下这个mQueue是什么时候被赋与对象(值)或者说初始化的。

找到一个Handler的构造:

public Handler(Callback callback, boolean async) {        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;//这里这里这里        mCallback = callback;        mAsynchronous = async;    }
例子中在为handler实例化的时候使用的无参构造直接调用了上面的构造:
public Handler() {        this(null, false);    }

       因为我们是在主线程中创建的hadler, 构造方法中调用Looper.myLooper()来获取Looper对象也就自然归属于主线程,也就是说这里的Looper和MessageQueue都是与UI线程相对应的,那例子中丢到这个messageQueue里的Message也自然由UI线程去取,并在loop()方法中执行msg.target.dispatchMessage(msg),这里msg.target就是刚刚被赋予的handler,最终由UI线程执行dispatchMessage()来处理这条消息。Looper.myLooper()来获取Looper对象期间的线程对应关系后边再分析。

public static void loop() {//创建Handler的线程必然执行了这个loop(),主线程默认执行了Looper.prepare()和Looper.loop()        final Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        final MessageQueue queue = me.mQueue;               for (;;) {//这个是主线程对应的Looper的loop方法的话,主线程的控制权会在这个for循环里直到App退出。            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }            msg.target.dispatchMessage(msg);//target 就是发送该msg的Handler对象            msg.recycleUnchecked();        }    }
      来看dispatchMessage:
public void dispatchMessage(Message msg) {        if (msg.callback != null) {//handler执行post相关的方法时,丢进来的Runnble对象会作为msg.callback,优先执行该回调            handleCallback(msg);//        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {//看到回调的的handleMessage,我们并没有在定义Handler的时候生成该回调。                    return;                }            }            handleMessage(msg);//终于执行了我们在Handler定义时覆写的handleMessage了!!!!        }    }
所以,UI线程执行了Looper 的 prepare()loop()并在loop的无限循环中执行了Handler的dispatchMessage(Message msg)和handleMessage(Message msg)。


总结:Handler对应一个线程,一个线程对应且只对应一个Looper对象,一个线程对应且只对应一个MessageQueue。(注意,没有说一个线程对应一个handler)

          在发送消息阶段,Handler sendMessage可以在任意线程发出,但是发出去的message会被入队到该发出消息的Handler对应的线程关联的消息队列。

          在消息的处理阶段,也是由发出消息的Handler对应的线程通过Looper.loop()方法来处理消息。

          到这里就可以从逻辑上解释,为什么我们自己新建的线程必须执行Looper.prepare()和Looper.loop()方法才能创建handler,因为不执行Looper.prepare(),handler发送的message不知道入队到哪个消息队列,发送消息无从谈起,不执行Looper.loop(),线程就没有不断地从消息队列取消息并处理的过程,处理消息也就无从谈起。

          当然,其实Handler提供了可以传入Looper参数的构造,子线程可以在不执行Looper.prepare()和Looper.loop()方法的情况下通过传入一个Looper对象创建handler,这时Looper对应的线程即是该handler对应的线程。所谓Looper对应的线程由其prepare()方法的调用线程决定。看Looper的prepare()方法:

    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));    }

prepare()方法通过ThreadLocal给执行prepare的线程绑定了一个Looper对象。

          ThreadLocal提供一种线程的变量管理机制,主要是set(Tvalue)和get(value)方法,通过调用sThreadLocal.set(value)可以为调用线程设置一个变量,这里就是给执行prepare的线程设置了一个looper对象,也是通过这个机制,保证了线程与Looper的一对一关系。上文提到的Looper.myLooper()获取的looper对象就是通过这个机制获取的。

public static @Nullable Looper myLooper() {        return sThreadLocal.get();    }
     通过sThreadLocal.get()就可以获取当前线程调用set方法时设置的值(对象),ThreadLocal保证了不同的线程调用get时,得到的变量都是该线程set的值(对象)。

         到这里就可以解答问题二了,在一个线程发送message后,对应的处理线程必须执行Looper.loop(),它的控制权就一定在loop()方法中不断循环,才能及时从消息队列中取出消息做相应的处理。

          问题三,先说答案:UI线程绑定的Handler的postDelay(Runnable r, Long delay)方法delay多长时间都不会阻塞UI线程,但是r的run()方法如果执行时间过长,会阻塞。
                    

 参考文章:

          《线程的私家小院:ThreadLocal》点击打开链接

           鸿洋大神的:点击打开链接

         《Android中的Handler解析》点击打开链接

阅读全文
0 0
原创粉丝点击