码迷,mamicode.com
首页 > 其他好文 > 详细

深入理解Handler

时间:2014-11-26 16:25:05      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:android   style   io   ar   color   os   使用   sp   for   

   Android开发人员对Handler,应该都很熟悉了,我们经常使用它的一个场景是当一些比较昂贵的耗时任务完成后,使用Handler通知到UI线程刷新UI,下面是代码

   1:          Thread taskThread = new Thread(new Runnable() {
   2:              
   3:              @Override
   4:              public void run() {
   5:                  //do some expensive tasks.
   6:                  downloadFile();
   7:                  mHandler.sendMessage(new Message());
   8:              }
   9:          });
  10:          taskThread.start();
 
  非常的简单,我们会在mHandler的 handleMessage 回调方法里面收到任务完成后传递的message对象。
今天我们深入去学习下Handler的实现源码。

* <p>There are two main uses for a Handler: (1) to schedule messages and
* runnables to be executed as some point in the future; and (2) to enqueue
* an action to be performed on a different thread than your own.

  这个是Handler源码里面的注释,说明了Handler的2个主要用途:1.安排消息和任务在未来的某个时刻执行。2.将一个需要执行的动作放入另外一个线程的任务队列中。我们刚才演示的代码,其实就是在非UI线程中,将一个刷新UI的动作通知到UI线程。
  下面我们看看Handler的默认构造器:
 
   1:  public Handler() {
   2:          if (FIND_POTENTIAL_LEAKS) {
   3:              final Class<? extends Handler> klass = getClass();
   4:              if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
   5:                      (klass.getModifiers() & Modifier.STATIC) == 0) {
   6:                  Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
   7:                      klass.getCanonicalName());
   8:              }
   9:          }
  10:   
  11:          mLooper = Looper.myLooper();
  12:          if (mLooper == null) {
  13:              throw new RuntimeException(
  14:                  "Can‘t create handler inside thread that has not called Looper.prepare()");
  15:          }
  16:          mQueue = mLooper.mQueue;
  17:          mCallback = null;
  18:      }
  
  这里我们首先要弄清楚2个对象,Looper mLooper和 MeesageQueue mQueue,Looper类,可以为每一个线程起一个
消息循环,然后每一个Looper内部会绑定一个MessageQueue对象,当有消息被放入消息队列时,消息循环会负责对消
息进行分发。
 
  为线程new一个Looper,调用Looper.parpare();
 
   1:      public static void prepare() {
   2:          if (sThreadLocal.get() != null) {
   3:              throw new RuntimeException("Only one Looper may be created per thread");
   4:          }
   5:          sThreadLocal.set(new Looper());
   6:      }
   1:  static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

 

 
  mThreadLocal保证每一个线程只会有一个Looper,重复创建会抛出异常。
 
  将线程绑定的Looper运行起来 ,调用Looper.loop();下面looper方法的一个片段
 
   1:     public static void loop() {
   2:          Looper me = myLooper();
   3:          if (me == null) {
   4:              throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread.");
   5:          }
   6:          MessageQueue queue = me.mQueue;
   7:          
   8:          // Make sure the identity of this thread is that of the local process,
   9:          // and keep track of what that identity token actually is.
  10:          Binder.clearCallingIdentity();
  11:          final long ident = Binder.clearCallingIdentity();
  12:          
  13:          while (true) {
  14:              Message msg = queue.next(); // might block
  15:              if (msg != null) {
  16:                  if (msg.target == null) {
  17:                      // No target is a magic identifier for the quit message.
  18:                      return;
  19:                  }

 

 
  在循环中,从消息队列取消息时,如果队列是空的,循环会阻塞,等待消息的到来。到这里,我们清楚了,起一个Looper需要调用parpare和loop二个方法,但是我们在最开始的实例代码里面并没有做这样的调用啊,为什么也能正常的发送消息?这是因为我们的app启动时就会有一个主线程即UI线程,在主线程初始化时的时候已经调用了prepareMainLooper 和 loop方法。所以我们在非UI线程创建Handler会有下面的实例代码:
 
   1:          Thread backgroundThread = new Thread(new Runnable() {
   2:              
   3:              @Override
   4:              public void run() {
   5:                  Looper.prepare();
   6:                  mBackgroundHandler = new Handler(){
   7:                      @Override
   8:                      public void handleMessage(Message msg) {
   9:                          super.handleMessage(msg);
  10:                      }
  11:                  };
  12:                  Looper.loop();
  13:              }
  14:          });

 

 
   这样我们就可以利用mHandler和mBackgroundHandler,自由的将任务插入到它们各自所属线程的消息队列中。
   现在我们再说说Message,Message类有二个比较重要的属性,Handler target和 Runnable callback,target表示这个消息要发给哪个handler去接收,如果某个消息没有target,Looper会认为这是结束消息循环的信号,于是Looper就会退出,所以一般我们用哪个Handler对象发送的消息,消息的target就是那个Handler对象,然后callback 就是我们上面说的 Handler二个用途的第一个用途,当从消息队列中取到消息后,会检查消息的target和callback,如果target不为空,callback也不为空,会执行callback的run方法。
  Looper的退出,我们可以调用Looper.myLooper().quit();
 
   1:  public void quit() {
   2:          Message msg = Message.obtain();
   3:          // NOTE: By enqueueing directly into the message queue, the
   4:          // message is left with a null target.  This is how we know it is
   5:          // a quit message.
   6:          mQueue.enqueueMessage(msg, 0);
   7:      }

 

             上面quit 的源码的注释也解释了,如果消息没有target,就是结束Looper 的消息。

         最后,关于Handler,就说这么多,希望上面的一些讲解对大家有帮助。

深入理解Handler

标签:android   style   io   ar   color   os   使用   sp   for   

原文地址:http://www.cnblogs.com/aliouswang-forever/p/4123284.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!