Android开发系列11——Handler消息处理机制

前言

  Android的消息处理机制其实就是另外一种形式的”事件处理“,这种机制主要是为了解决Android应用的多线程问题。

理解Handler的消息机制,首先要从几个方面了解Handler消息处理机制。

  • Handler是什么?(Handler的概念)
  • Handler可以做什么?(Handler的用途)
  • Handler怎么使用?(Handler的用法)

其次,需要了解Handler消息处理过程中用到的类,这些类具体是什么怎么用等。

一、Handler

Handler具体的解释和方法可以参考:Handler.java类文件。

1.Handler是什么?(Handler的概念)

A Handler allows you to send and process {@link Message} and Runnable objects associated with a thread’s {@link MessageQueue}. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread message queue of the thread that is creating it – from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

简单翻译:

Handler是一个可以通过关联一个消息队列来发送和处理消息,发送或处理Runnable对象的一个处理程序,每个Handler都关联单个的线程和消息队列,当你创建一个新的Handler,Handler将绑定到线程消息队列(假设:A)上,从正在创建Handler对象时间点所在的线程就是绑定的线程消息队列(在那个线程创建,就在那个线程绑定消息队列),这个Handler为消息队列(假设:A)提供消息和Runnable对象,执行从消息队列释放出来的消息和Runnable对象。

2.Handler可以做什么?(Handler的用途)

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

简单翻译:

Handler有两个主要的用途:

  • 1.在将来的摸一个时间点执行 消息和 Runnable
  • 2.将一个动作(Action)放在不同于所在的线程上执行

3.Handler怎么使用?(Handler的用法)

Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler’s handleMessage(Message) method (requiring that you implement a subclass of Handler).


When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.


When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will then be scheduled in the Handler’s message queue and processed when appropriate.

简单翻译:

通过重写post(Runnable)、postAtTime(Runnable, long)、postDelayed(Runnable, long)、sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message, long)、sendMessageDelayed(Message, long)来完成发送消息。当前版本允许你通过消息队列接受一个Runnable对象,sendMessage方法当前版本允许你将一个包的数据通过消息队列的方式处理,但是你需要重写Handler的handleMessage方法


当发布<处理>和发送一个Handler时,你既可以在消息队列准备就绪立即处理,或者指明一个延迟处理时间或者绝对的时间(系统具体时间)去执行,后边这两个都允许你完成,在超时、ticks(系统的相对时间单位)和其他时间段为基础的行为


即当一个进程被应用程序创建时,它的主线程会运行一个消息队列负责管理它创建的高层应用程序对象(如Activity、Broadcast Receiver等)和任何它的窗口创建的对象,你可以通过一个Handler,创建自己的线程来实现与主线程之间的交互,但前提是你得在你的线程重写sendMessage方法并写上一行行代码,这样你给定的Runnable或者Message将被MessageQueue(消息队列)预定,并在合适的时间处理

二、Handler相关的类

1.Looper

Looper的Class文件中,查看Looper的详细解释

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call {@link #prepare} in the thread that is to run the loop, and then{@link #loop} to have it process messages until the loop is stopped.


Most interaction with a message loop is through the{@link Handler} class.


This is a typical example of the implementation of a Looper thread,using the separation of {@link #prepare} and {@link #loop} to create an initial Handler to communicate with the Looper.

简单的翻译:

Looper被用于线程运行的消息循环的类,默认线程并没有和消息循序之间相互关联,所以创建一个Looper,在Thread中Looper调用prepare运行消息循环,让后调用loop()让它循环处理消息,知道循环停止。
很多和消息循环的交互都是通过Handler类
这是一个典型Looper线程的实例,它用prepare()和loop()的分割来创建一个初始化的Handler与Looper进行通信。

class LooperThread extends Thread {
     public Handler mHandler;

     public void run() {
         Looper.prepare();

         mHandler = new Handler() {
             public void handleMessage(Message msg) {
                 // process incoming messages here
             }
         };
         Looper.loop();
     }
 }

2.Message

Message的Class文件中,查看Message的详细解释

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.

简单翻译:

定义一条包含描述和任意数据对象的消息,该对象可以是发送到{@link Handler}。 该对象包含两个额外的int字段和一个额外的对象字段,使您在许多情况下不进行分配。


虽然Message的构造函数是公共的,但最好的获取方法其中之一是调用{@link #obtainMessage.obtain()}或其中之一{@link Handler#obtainMessage Handler.obtainMessage()}方法,该方法将 它们来自回收对象池。

3.MessageQueue

Low-level class holding the list of messages to be dispatched by a {@link Looper}. Messages are not added directly to a MessageQueue, but rather through {@link Handler} objects associated with the Looper.


You can retrieve the MessageQueue for the current thread with {@link Looper#myQueue() Looper.myQueue()}.

简单的翻译:

包含{@link Looper}要分派的消息列表的低级类。 消息不是直接添加到MessageQueue,而是通过与Looper关联的{@link Handler}对象添加。


您可以使用{@link Looper#myQueue()Looper.myQueue()}检索当前线程的MessageQueue。

三、Handler运行流程

通过上述的概念描述了Handler运行过程中的所有Class,接下来会详细讲解一下Handler的的运行的流程,以及相关的Class在Handler运行过程中的作用。

  • Message: Handler接收 和 处理的消息对象。
  • Looper: 每个线程只能拥有一个Looper,它的loop方法负责读取MessageQueue中的消息,读到消息之后就把消息交给发送消息的Handler进行处理。
  • MessageQueue: 消息队列,采用先进先出的方式管理Message。程序在创建Looper对象时,会在它的构造器中创建MessageQueue对象。
  • Handler: 它的作用主要有两个——发送消息和处理消息。

由于Handler的作用是:发送消息和处理消息,发送Message消息,必须有一个MessageQueue进行接收,而MessageQueue必须由Looper负责管理。如下图:

1.发送Message消息
2.Message必须被Message保存
3.MessageQueue需要Looper来管理
Handler创建需要关联一个Looper
Handler
Message
Looper
MessageQueue

所以Handler正常工作之前,必须在当前线程中必须一个Looper对象。(默认线程内比没有Looper,但在UI主线中,一直存在一个Looper对象运行

1.Handler类底层分析运行流程

Handler类内的方法可以分为三类:(如下图)

  • 构造Handler函数
  • 发送Message消息
  • 接收Message消息
  • 从MessageQueue中获取Message消息

Handler类中的属性对象:

 @UnsupportedAppUsage
    final Looper mLooper;        // Looper 对象
    final MessageQueue mQueue;   // 消息管理类
    @UnsupportedAppUsage
    final Callback mCallback;     // CallBack 回调
    final boolean mAsynchronous;    //  异步标识
    @UnsupportedAppUsage
    IMessenger mMessenger;      //消息

Handler类方法Handler类方法

1)构造Handler方法

无参数的Handler构造方法(默认读取当前线程中的Looper,如果不存在会抛出异常

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

含有参数的Handler构造方法:

  • 从构造方法上的解释可知,Handler上的mQueue是Looper对象内的。(和上边讲述的一致)
  • callback 这个callback接口实现handle消息。
/**
     * Use the {@link Looper} for the current thread with the specified callback interface
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(@Nullable 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();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

/**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by conditions such as display vsync.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

2) Handler中的callback

从Handler类方法中,找到callback对应的方法,从官方解释:Handler的子类实现Callback接口(handleMessage)才能处理Handler接收到的消息。

/**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     */
    public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        boolean handleMessage(@NonNull Message msg);
    }
    
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(@NonNull Message msg) {
    }

总之,Handler在初始化之前,Handler初始化所在线程必须有Looper对象(只有UI主线程才有Looper),所以在子线程中使用Handler,需要创建Looper对象。

四、Looper的运行

Looper类的方法如下:
Looper类方法
Looper的构造方法是一个私有的方法,在用户层面无法调用这个构造方法来构造Looper的对象。

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

Looper有一个经典在线程中的例子,用于创建一个新的Looper对象。(由于除UI主线程之外的线程,都不会创建和关联Looper对象,必须创建一个Looper对象)

class LooperThread extends Thread {
     public Handler mHandler;

     public void run() {
         Looper.prepare();

         mHandler = new Handler() {
             public void handleMessage(Message msg) {
                 // process incoming messages here
             }
         };
         Looper.loop();
     }
 }

所以Looper在线程中,Handler进行传值需要进行两步操作:

  • Looper.prepare();
  • Looper.loop();

Looper.prepare()

/** 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()}.
      */
    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)); // 创建一个新的Looper对象
    }

	// 创建Looper对象
	private Looper(boolean quitAllowed) {
      mQueue = new MessageQueue(quitAllowed);
      mThread = Thread.currentThread();   // 当前所在的线程
  }

Looper在调用Looper.prepare(), 创建一个新的Looper对象( sThreadLocal.set(new Looper(quitAllowed));)。并且创建Handler,把Handler和当前线程中的Looper关联起来。

Looper.loop();

 /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the 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();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();
        }
    }


/**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

从Looper.loop()的源码,可以看出loop对消息队列进行运行,显现Handler的消息传递。

总结:

  Handler主要是用于线程之间的异步通信管理的抽象类,线程之间传递的的Message需要通过Looper的Message队列管理,Looper是Handler实现线程之间消息传递比不缺少的一个循环消息管理对象。

  主线程中存在Looper对象。所以不需要创建,只需要进行发送消息和接收消息即可。

  其他线程中Looper对象需要通过prepare()来创建Looper,通过loop()来运行Looper。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章