从源码深入理解Android Handler异步消息处理机制

版权声明:本文出自wdmzszly的博客,转载必须注明出处。 https://blog.csdn.net/wdmzszly/article/details/81941116

目录

概述

Handler机制的简单介绍

Handler机制的一般使用场景

源码分析

Looper

Handler

主线程Looper.prepare()

需要注意的地方


概述

Handler机制的简单介绍

Android的消息异步处理机制,是每个Android程序员都应该掌握的。下面是这几个类的官方介绍,简单的翻译下,大家都应该看得懂。

Handler

扫描二维码关注公众号,回复: 3692739 查看本文章

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 bound to the thread/messageQueue 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对象到MessageQueue里面,也可以处理这些从MessageQueue里面取出来的消息和Runnable对象。每一个Handler实例都跟一个线程和MessageQueue绑定。当你创建一个新的Handler时,handler对象将会跟创建时所在的线程的线程实例和MessageQueue绑定。从这点可以知道,handler将会把消息和runnable实例发送到和它绑定的messagequeue,并且执行或处理从这些队列分发出来的消息和Runnable对象。

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 Looper.prepare() in the thread that is to run the loop, and then loop to have it process messages until the loop is stopped.Most interaction with a message loop is through the Handler class.

MessageQueue

Low-level class holding the list of messages to be dispatched by a Looper. Messages are not added directly to a MessageQueue,but rather through Handler objects associated with the Looper.You can retrieve the MessageQueue for the current thread with Looper.myQueue().

简单的说,MessageQueue本质上内部有个Message的单链表,通过Handler对象发送到链表里面,又Looper.loop()方法里面分发出来。

Message

Defines a message containing a description and arbitrary data object that can be sent to a 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 Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.

Handler机制大概原理如下图所示,首先Handler把Message发送到MessageQueue,同时Looper不断的从MessageQueue取出待处理的Message,然后回调Handler的dispatchMessage方法,把消息交给Handler去处理。

Handler机制的一般使用场景

public class HandlerActivity extends AppCompatActivity {
​
    private TextView textView;
    Handler handler = new MyHandler(this);
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        textView = findViewById(R.id.text);
​
        new Thread(new Runnable() {
            @Override
            public void run() {
                //模拟从网络获取消息
                String text = getTextFromNet();
                Message message = Message.obtain();
                message.what = 0;
                message.obj = text;
                handler.sendMessage(message);
            }
        }).start();
    }
​
    private void setText(String text){
        textView.setText(text);
    }
​
    private String getTextFromNet(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "text text text";
    }
​
    static class MyHandler extends Handler{
        private WeakReference<HandlerActivity> activityRef;
        private MyHandler(HandlerActivity activity){
            this.activityRef = new WeakReference<>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            if (activityRef!=null) {
                HandlerActivity activity = activityRef.get();
                if (activity != null) {
                    switch (msg.what) {
                        case 0:
                            String text = (String) msg.obj;
                            activity.setText(text);
                            break;
                    }
                }
            }
        }
    }
}
​

以上是一个模拟在子线程去访问网络获取一个文本信息,然后通过主线程把它显示到UI上面。下面从源码分析Handler的工作原理。

源码分析

Looper

想要使用Handler机制处理消息,首先要调用Looper.prepare()方法

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是ThreadLocal的一个实例,它用于储存当前线程变量 。可以看到一个线程只能调用一次Looper.prepare()方法,否则将抛出RuntimeException。prepare()方法内部调用了Looper的构造方法创建了一个Looper实例

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

Looper的构造方法创建了MessageQueue,并且绑定了当前线程。注意Looper的构造方法为私有方法,它只在prepare()方法内部调用,而一个线程只能调用一次prepare()方法,所以一个线程只有一个Looper实例和一个MessageQueue实例。

然后我们看Looper.Looper()方法。

public static void loop() {
    final Looper me = myLooper();//获取当前线程的Looper对象
    if (me == null) {//loop()要在prepare()之后调用
        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 (;;) {//循环从MessageQueue中取出Message
        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);
        }
​
        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;
        try {
            msg.target.dispatchMessage(msg);//这里分发消息
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            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();
    }
}

Looper.loop()方法内部首先调用myLooper()方法拿到当前线程的Looper对象

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

如果对象为空则抛出错误。所以loop()方法要在prepare()方法后面调用。接下来可以看到Loope()方法内23行有个for循环,不断从MessageQueue对象中不断取出Message,然后通过第57行语句msg.target.dispatchMessage(msg)分发Message对象。msg.target实际是Handler对象,后面会具体介绍到。

Handler

接着我们看Handler

public Handler() {
    this(null, false);
}
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();
    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;
}

在Handler的构造方法内会先拿到当前线程的Looper对象,然后判断是否为空,如果为空则抛出错误。在这里,handler对象会跟当前线程的Looper对象和MessageQueue对象绑定,即持有他们的引用。

在使用Handler对象发送Message的时候,我们一般会调用handler.sendMessage(msg)或者sendMessageDelayed()方法,不过在方法内部最终都会调用sendMessageAtTime()方法。

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

在sendMessageAtTime()方法里面又调用enqueueMessage(queue, msg, uptimeMillis);

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

可以看到msg.target = this;把当前对象赋给了msg.target,也就是我们在介绍Looper.loop()方法时候提到的msg.target是Handler对象。最后调用了MessageQueue的enqueueMessage()方法把消息存到MessageQueue对象里面,MessageQueue的enqueueMessage()方法

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }
​
    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }
​
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }
​
        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

从第22到25行代码可以知道,Message的入队方式是根据回调的时间决定入队的位置的,也就是when参数,when参数小的排在队列的前面,参数大的排在后面。

我们前面说过,Looper.loop()方法会不断的从MessageQueue里面取出待处理的Message对象然后分发给Handler对象去处理。也就是msg.target.dispatchMessage(msg)语句,那么我们看下Handler的dispatchMessage(msg)里面到底是怎样实现的。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);//情况一
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {//情况二
                return;
            }
        }
        handleMessage(msg);//情况三
    }
}

可以看到,如果Message的callback不为空,则优先处理;如果Message的callback为空,判断handler的callback是否为空,如果不为空则回调handler.mCallback的handleMessage(msg)方法来处理消息,最后才会交给handler的handleMessage(msg)方法处理。

//if (msg.callback != null) 
private static void handleCallback(Message message) {
    message.callback.run();
}

那么什么情况下msg.callback才不会为空呢?

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

可以看到当调用handler的post(runnable)方法的时候,会调用getPostMessage()方法,在该方法里面,会把runnable参数赋给Message对象的callback属性,并返回Message对象。也就是调用handler的post(runnable)方法发送消息,在dispatchMessage方法里走的是情况一。

同样的,我们看下handler的callback

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

在构造handler对象的时候,给它传入callback就可以了,这时候走的是情况二。handler.mCallback.handleMessage(msg)如果返回true则表示该方法已经处理消息,就不在交给handler.handleMessage(msg)方法,否则交给它处理,就会到情况三。

public void handleMessage(Message msg) {
}

可以看到handler.handleMessage(msg)是个空方法,里面没有实现。所以使用的时候要重写该方法。

主线程Looper.prepare()

前面我们说到一个线程想要使用Handler机制处理消息,首先要调用Looper.prepare()方法。那么我们没有对主线程调用该方法,为什么还是可以使用handler呢。原因在于主线程的Looper.prepare()方法是在ActivityThread.main()方法里面调用的,main()方法是Android应用程序的入口方法。

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
​
    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);
​
    Environment.initForCurrentUser();
​
    // Set the reporter for event logging in libcore
    EventLogger.setReporter(new EventLoggingReporter());
​
    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);
​
    Process.setArgV0("<pre-initialized>");
​
    Looper.prepareMainLooper();//这里调用了主线程的prepareMainLooper()方法
​
   ...
}

需要注意的地方

  • 如果想要在子线程做更新UI操作,那么可以使用handler在子线程发送消息交给主线程处理,但是这里需要注意handler实例应该在主线程创建,或者创建handler给它传入Looper.getMainLooper()返回的主线程Looper对象。

Handler handler = new Handler(Looper.getMainLooper());
  • 当要创建一个Message对象,可以调用new Message()的构造方法创建。但最好的办法是使用Message.obtain() 或者 Handler.obtainMessage() 方法,因为两个方法是从一个message对象回收池里面获取message对象的,节省了创建新的message对象所需要的消耗。

猜你喜欢

转载自blog.csdn.net/wdmzszly/article/details/81941116