Handler消息机制分析

来源:互联网 发布:兄弟连mysql视频教程 编辑:程序博客网 时间:2024/05/22 08:22

Handler消息机制分析

标签(空格分隔): Android Handler


概述

  1. handler允许你发送和处理与MessageQueue消息队列有关的Message和Runnable对象
  2. 每个hanler实例与一个线程和该线程的队列相联系,它受限于该线程和该消息队列

handler有两种用法:

  1. 用于将来调度message和执行Runable对象
  2. 将一个不同线程的行为放入队列
    调度信息方法:

    post
    postAtTime
    postDelay

    sendEmptyMessage
    sendMessage
    sendMessageAtTime
    sendMessageDelayed

    提醒:post方法允许你放入一个被MessageQueue消息队列调用的Runable对象
    sendMessage方法允许将包含一包数据的Message对象放入队列。该Message消息将由Handler的HandlerMessage方法处理(当然你需要实现一个Handler的子类)

当使用post或者send方法的时候
1. 你可以允许他们立即执行(消息队列打算这个干的时候)
2. 指定一个时间延时(即Delay)
3. 指定一个绝对时间(即AtTime)

当一个进程为你的application应用创建的时候,它的主线程从事于运行一个消息队列,该消息队列关注管理顶级水平的一个应用对象(比如activitis,broadcast receiver等)和他们创建的窗口。你可以创建你自己的线程,然后在后台通过Handler与主应用线程交流(这些可以在你的线程中通过前面所说的post,sendMessage方法实现,给定的Message消息和Runnable对象会在handler的消息队列中调度并在适当的时候处理)。


消息处理机制(从发送消息到处理消息)

发送消息

从上可知发送消息主要有send和post方法,我们来看下

/*   将消息加入消息队列,放在所有消息后面    @param msg 参数   @uptimemillis 执行确切时间,精确到微妙(基于SystemClock时间)   @return true成功加入队列,false失败(通常是因为处理消息队列的looper推出了)*/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);//加入消息队列}

一问:这里我们看见了mQuenue,这是何时创建呢?

我们可以在两个Hanler构造函数中看见

   1. public Handler(Callback callback, boolean async) {        当FIND_POTENTIAL_LEAKS设置为真会检测extends Handler的非静态的匿名,本地和成员类。        因为这种类可能会发生内存泄露。        if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }        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;    }    我们看见是由mLooper创建   2. public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;//一个接口,里面有一个抽象方法handleMessage(Message msg);        mAsynchronous = async;//设置handler是否进行异步处理    }    我们同样可以看见是由looper创建

二问:looper是什么何时创建消息队列
looper概述:
looper用于为一个线程运行消息循环,线程默认是没有与之相关的消息循环的。调用looper的prepare()可以在线程中创建一个消息循环来管理循环。looper的loop操作使之处理消息,知道loop终止。

一个常见的例子是:

  class LooperThread extends Thread {      public Handler mHandler;      public void run() {          Looper.prepare();//初始化当前线程为一个looper          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };//完成了与looper的绑定。分析如下          Looper.loop();//运行当前线程的消息队列      }  }

注:
在主线程中运行的部分,都可以直接使用Handler,因为在主线程启动的过程中(ActivityThread的main函数里)会调用Looper.prepareMainLooper(),Looper类中也直接定义了一个static的looper实例sMainLooper用于存放主线程的Looper,可以通过静态方法获取到。 因此,凡是在主线程中运行的代码段里 都可以直接new Handler()而不用去绑定Looper,MessageQueue;

    public static void main(String[] args) {        ...        Looper.prepareMainLooper();//初始化当前线程作为一个Looper,并将之标记为应用的主Looper.        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

looper与handler绑定过程

    public Handler() {        this(null, false);    }    this会使用如下handler。可知looper通过Looper.myLooper在线程中完成绑定    public Handler(Callback callback, boolean async) {        if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }        mLooper = Looper.myLooper();//返回与当前线程关联的looper对象        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;    }

接下来如何在Looper中与线程绑定:
从上面可以知道,在prepare函数中初始化了一个线程为Looper:

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

sThreadLocal在Looper中的定义

// sThreadLocal.get() will return null unless you’ve called prepare().

 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

在此补充ThreadLocal概念:
1. ThreadLocal实现了一个Thread-local仓库,对于每一个线程都有自己的值。
2. 所有线程共享同样的ThreadLocal对象,但是每个线程访问时获取的是不同的值
3. 某个线程对ThreadLocal的变量的修改不会影响其他线程
4. 支持null值

回到正题:Looper是如何创建消息队列

private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);    mThread = Thread.currentThread();}

由此看出在Looper构造时已经创建

Handler消息如何执行

handler创建后发送的消息就会进入消息队列。此时如果没有为handler单独创建线程,则执行的是ActivityMain的Looper.loop(),否则执行当前线程的Looper.loop();

public static void 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;// Make sure the identity of this thread is that of the local process,// and keep track of what that identity token actually is.Binder.clearCallingIdentity();//重置当前线程IPC(进程间通信)的标识符final long ident = Binder.clearCallingIdentity();for (;;) {    Message msg = queue.next(); // might block    if (msg == null) {        // No message indicates that the message queue is quitting.        return;    }    // This must be in a local variable, in case a UI event sets the logger    Printer logging = me.mLogging;  //日志输出    if (logging != null) {        logging.println(">>>>> Dispatching to " + msg.target + " " +                msg.callback + ": " + msg.what);    }    msg.target.dispatchMessage(msg);  //处理消息    if (logging != null) {        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);    }    // Make sure that during the course of dispatching the    // identity of the thread wasn't corrupted.    final long newIdent = Binder.clearCallingIdentity();    if (ident != newIdent) {        Log.wtf(TAG, "Thread identity changed from 0x"                + Long.toHexString(ident) + " to 0x"                + Long.toHexString(newIdent) + " while dispatching to "                + msg.target.getClass().getName() + " "                + msg.callback + " what=" + msg.what);    }    msg.recycleUnchecked();//将消息实例返回到全局池}}

可以看到是msg.target.dispatchMessage(msg)在处理消息
而在Message中定义有这样一个字段:

public final class Message implements Parcelable {     ...    /*package*/ Handler target;     ...}

可知消息正是交给了Handler处理。
我们再看下发送消息过程
在上面sendMessageAtTime的我们可以看见函数enqueueMessage中 msg.target = this;

      private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;//给target赋值为当前handler        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

所以,消息由handler的dispatchMessage分配

    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);//判断msg的callback是否为空,不为空则调用handleCallback        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {//判断mCallBack是否为空,不为空则调用其handleMessage                    return;                 }            }            handleMessage(msg);//由子类实现         }    }
如下,可以看见handleCallback只是调用callback(只是Runnable,一个赋值个Message的线程)
    private static void handleCallback(Message message) {        message.callback.run();    }

也就是说最后消息就传给了我们自定义的handleMessage;

呼!终于分析完了,不足之处请指正。

0 0