androidFloatTaskApp

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

2017-05-22  本文已影响993人  AndroidTony

标签: android 线程 handler


1 什么是handler

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

2 handler的作用

3 Handler的使用原理

4 Handler相关概念

4.1 Message

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

/**

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}.
 * 
 * <p>Note that Parcelable objects here are not supported prior to
 * the {@link android.os.Build.VERSION_CODES#FROYO} release.
 */
public Object obj;

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 整个过程

5 Handler的使用步骤

5.1 获取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;
            }
        }
    };
  *  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()开始轮询消息。

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);
上一篇下一篇

猜你喜欢

热点阅读