Android 线程通信之Handler -- 一篇文章彻底弄懂Handler

标签: android 线程 handler


1 什么是handler

Handler中文翻译为“处理者”,这里的“处理”顾名思义是在某种条件发生之后所要进行的操作。

2 handler的作用

  • Handler主要用于异步线程进行通信。这种方式也是Android官方推荐的方式,比较节省性能。我们知道,Android主线程(UI线程)主要负责UI绘制,耗时操作不能放在主线程执行,要不然容易造成卡顿,严重时会ANR。在Android中最常使用Handler的场景就是主线程调用子线程去进行网络访问,子线程在获取到网络访问的返回结果并处理数据之后,通知主线程去更新UI。例如下拉刷新。Handler在这里充当的是消息的发送者和接收者的角色。所谓消息,也就是前面讲的某种特定条件发生之后的状态。例如获取完网络数据之后,获取数据成功或者失败,就是不同的状态,需要发送不同的消息。
  • 另外,Handler还用于延时处理某个任务。

3 Handler的使用原理

  • Handler既是发送者也是接收处理者,一个消息发送出来,交由哪个Handler去处理,这个完全取决于这个消息的发送者是哪个Handler。即一个Handler发送的消息,只能交由自己去处理。要做到异步线程进行通信,关键在于在A线程中拿到B线程的Handler,拿到之后就可以使用B线程的Handler去发送消息,交由B线程去处理消息了。线程与Handler之间是多对一的关系,一个线程可以有多个Handler,一个Handler只能且必须绑定一个线程。一个线程有多个Handler(使用场景会在后面介绍),用于处理不用类型的消息。
  • 使用Handler的表现形式有两种:
    (1)通过发送消息(sendMessage方法)接收消息(接收消息即回调该Handler的handleMessage方法)并处理的形式;
    (2)通过发送Runnable对象的形式,直接让该Handler所在线程执行其run方法。即调用post(Runnabler)方法。需要注意的是:(1)该Runnable也会被包装成一个消息的形式进行传递。(2)整个过程并没有另外新建线程,该Runnable在Handler所在线程执行。

4 Handler相关概念

4.1 Message

Message用来记录需要传递的信息。该类继承自Parcelable类。
官方描述为:

/**

  • Defines a message containing a description and arbitrary data object that can be

  • sent to a {@link Handler}. This object contains two extra int fields and an

  • extra object field that allow you to not do allocations in many cases.

  • While the constructor of Message is public, the best way to get

  • one of these is to call {@link #obtain Message.obtain()} or one of the

  • {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull

  • them from a pool of recycled objects.
    */

  • Message类默认定义了两个int和一个Object(传递对象)用于传输常用的数据,如果不够用,则使用Bundle。

public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
public int what;

/**
 * arg1 and arg2 are lower-cost alternatives to using
 * {@link #setData(Bundle) setData()} if you only need to store a
 * few integer values.
 */
public int arg1; 

/**
 * arg1 and arg2 are lower-cost alternatives to using
 * {@link #setData(Bundle) setData()} if you only need to store a
 * few integer values.
 */
public int arg2;

/**
 * An arbitrary object to send to the recipient.  When using
 * {@link Messenger} to send the message across processes this can only
 * be non-null if it contains a Parcelable of a framework class (not one
 * implemented by the application).   For other data transfer use
 * {@link #setData}.
 * 
 * 

Note that Parcelable objects here are not supported prior to * the {@link android.os.Build.VERSION_CODES#FROYO} release. */ public Object obj;

  • 另外,还定义了一个target,表示与该Message绑定的Handler。一个callback,当使用post(Runnable r)时,r会被包装成员一个Message,这个Message的callback就是传入的r。

4.2 MessageQueue

Handler发送的消息,可以立即处理也可以延时处理,肯定需要一个容器来存放消息。MessageQueue就是这样一个消息队列。

4.3 Looper

Message被Handler发送出来,会被放入MessageQueue中,放入其中的Message在条件成熟的时候会被取出来,交由Handler去处理。整个过程中还需要一个对象来执行获取并放入,取出并交给对应Handler的工作。这个工作就由Looper来完成。
Looper需要执行两个过程:(1)与线程进行绑定prepare方法(2)读取消息队列中的消息并交由Handler进行处理loop方法

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

** 4.4 整个过程

  • 一个线程对应一个Looper、一个MessageQueue以及多个Handler、多个Message
  • 一个Message对象,在被发送的时候将发送该Message对象的Handler对象的引用保存到target成员变量上,looper在轮询Message的时候,就直接把该Message交给message.target这个Handler去处理就可以了。
  • 在调用Handler的sendMessage后,会把Message对象放入一个MessageQueue队列,该队列属于某个Looper对象,每个Looper对象通过 ThreadLocal.set(new Looper())跟一个Thread绑定了。Looper对象所属的线程在Looper.Loop方法中循环执行如下步骤:从MessageQueue队列读取 Message对象,并把Message对象交由Handler处理,调用Handler的dispatchMessage方法。

5 Handler的使用步骤

5.1 获取Handler

  • 当前Thread已经有Looper的情况(主线程默认已经在ActivityThread的main方法中初始化Looper),则直接new一个Handler。可以选择重写或者不重写handleMessage方法(不重写将只能使用post的方式调用)。此时该Handler会自动绑定到当前线程。
    官方解释为:

/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/

public Handler() {
        this(null, false);
    }

/**
* Subclasses must implement this to receive messages.
*/

public void handleMessage(Message msg) {
    }

实例:

public class MyActivity extends BaseActivity{
    private static final String TAG = "MyActivity";
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CommonConstants.MSG_REFRESH_VIDEO_ITEM:
                    doSomething();
                    break;
                default:
                    break;
            }
        }
    };
  • 当前线程还没有Looper的情况,则需要先初始化当前线程的Looper,然后new一个Handler。
    初始化当前Looper的方式为:
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
   /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
  *          Looper.loop();
  *      }
  *  }

在初始化Handler之前需要调用Lopper.prepare()方法初始化Looper,初始化Handler之后调用Looper.loop()开始轮询消息。

  • 如果在子线程使用主线程的Handler,可以使用new Handler(Looper.getMainLooper())的方法得到。

5.2 使用Handler发送消息

handler发送消息的方法是比较多,常用的就包括
获取消息包括Runnable对象和message对象两种,获取Message的方式包括:
1 直接new一个Message,设置what等参数(不推荐)。
2 通过handler获取复用的Message(推荐)

  • handler.obtainMessage()
  • handler.obtainMessage(int what)
  • obtainMessage(int what, Object obj)
  • ......

3 直接发送空Message,只有what

  • sendEmptyMessage(int what)

发送消息的方法:

post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message) 将消息发送到消息队列
msg.sendToTarget() 将消息发送到消息队列
sendMessageAtTime(Message,long) 定时将消息发送到消息队列
sendMessageDelayed(Message,long) 延迟一定时间后,将消息发送到消息队列

5.3 使用Handler接收消息并处理

在Handler的handlerMessage中根据what去处理相应逻辑。

6 发送Runnable和发送Message的区别

post方式:发送runnable,实际上是把runnable对象设置为一个Message的成员变量callback之后,发送该Message。最后都是走到sendMessageDelayed方法当中。唯一的区别在于,post方式的Message的callback不是null,send方式发送的Message的callback是null。
1

 public final boolean post(Runnable r){
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
 private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

2

  public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

send方式:
1

public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

2

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

Looper在处理的时候:如果msg.callback的是null,则直接调用其run方法;如果为空,则交由handlerMessage去处理。
1

 public static void loop() {
        ...
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ...
    }

2

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

7 实例

实例1:handler定时器
需求:在主线程每隔一段时间执行一次
代码:
1

 private static long mDelayMillis = 1000;
  Handler mHandler = new Handler(Lopper.getMainLooper());
  Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    ...
                    mHandler.postDelayed(this, mDelayMillis);
            };
  mHandler.post(runnable);
  //如果要取消任务
   mHandler.removeCallbacks(runnable);

你可能感兴趣的:(Android 线程通信之Handler -- 一篇文章彻底弄懂Handler)