深入理解Handler

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,就说这么多,希望上面的一些讲解对大家有帮助。

时间: 2024-11-09 03:04:20

深入理解Handler的相关文章

【第二课】深入理解Handler

简要讲解Handler是做什么的 我们知道,在Android中,app启动会启动一个进程一个线程——UI线程,UI线程是主线程,并且不允许这个线程阻塞超过5秒,一旦超过5秒就会ANR. 所以较为耗时的工作(网络请求.文件读写)一般都是开一个线程来处理的,但其他的工作线程不可以直接操作Android的UI,UI只能在UI线程操作.所以就需要一个进程间通信机制来让工作线程的消息传递到UI线程,从而在UI线程改变UI. 这个通信机制就是Handler,普遍的做法就是通过重载Handler的handle

全面理解Handler第一步:理解消息队列,手写消息队列

前言 Handler机制这个话题,算是烂大街的内容.但是为什么偏偏重拿出来"炒一波冷饭"呢?因为自己发现这"冷饭"好像吃的不是很明白.最近在思考几个问题,发现以之前对Handler机制的了解是在过于浅显.什么问题? Handler机制存在的意义是什么?能否用其他方式替换? Looper.loop();是一个死循环,为什么没有阻塞主线程?用什么样的方式解决死循环的问题? 如果透彻的了解Handler,以及线程的知识.是肯定不会有这些疑问的,因为以上问题本身就存在问题.

彻底理解handler的实现原理

说到handler大家都很熟悉,自己也用了很久,再此总结一下 从handler的源码角度看看handler是如何执行的. 涉及到的内容: Loop Message MessageQueue ThreadLocal Hadnler 这些东西还是挺多的.那么我们先看一个栗子吧 public class MainActivity extends Activity { private static final String TAG = "MainActivity"; @Override pro

理解 Handler

今天对Handler 做了一个整体的理解 转一篇园子里的博文 已经写的很详细 本文的思维导图: 众所周知,Handler是Android中用来处理异步的类,为什么有时候可以直接使用子线程,而有时候要使用Handler呢?网上有很多教程讲解Handler,个人认为,很多教程都将Handler复杂化,学会Handler的使用是一件非常简单的事. 1.为什么需要Handler? 我们有这样一个需求,在界面中有一个TextView,当系统启动时,每隔一秒就更改里面的文字为:“当前值: ” + i,其中i

安卓开发_深入理解Handler消息传递机制

一.概述 因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面 二.消息类(Message) 消息类是存放在MessageQueue中的,而一个MessageQueue中可以包含多个Message对象 每一个Message对象可以通过Message.obtain()或者Handler.obtainMessage()方法获得 一个Message具有的属性: 属性 类型 介绍 arg1 int 存放整型数

文章标题 带你从源码的角度去理解Handler

一.概述 Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念.那么什么叫异步消息处理线程呢? 异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环.若消息队列为空,线程则会阻塞等待. 说了这一堆,那么和Handler . Looper .Message有啥关系?其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断

《Android进阶》之第三篇 深入理解Handler

Handler相关说明: A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is

深入理解 Handler 消息机制

记得很多年前的一次面试中,面试官问了这么一个问题,你在项目中一般如何实现线程切换? 他的本意应该是考察 RxJava 的使用,只是我的答案是 Handler,他也就没有再追问下去了.在早期 Android 开发的荒芜时代,Handler 的确承担了项目中大部分的线程切换工作,通常包括子线程更新 UI 和消息传递.不光在我们自己的应用中,在整个 Android 体系中,Handler 消息机制也是极其重要的,不亚于 Binder 的地位. ActivityThread.java 中的内部类 H 就

深入理解Android消息处理系统——Looper、Handler、Thread

Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制.实际上谷歌参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制. Android通过Looper.Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环). 本文深入介绍一下Android消息处理系统原理. Android系统中Looper负责管理线程的消息队列和消息循环,具体实现请参考Looper的源码. 可以通过Loop.myLooper(