Android源码——Handler机制(一)

Handler机制概述

介绍

Handler是Android消息机制的上层接口。Handler可以将一个任务切换到Handler所在的线程中去执行。通常情况下,Handler的使用场景就是更新UI。

如下就是使用消息机制的一个简单实例:

public class BasicActivity extends AppCompatActivity {

    private static final String TAG = "BasicActivity";

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.i(TAG, msg.what);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                
                // 耗时操作.....
                
                Message message = Message.obtain();
                message.what = 1;
                mHandler.sendMessage(message);
            }
        }).start();
    }
}

在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新UI。这便是消息机制的典型应用场景。我们通常只会接触到Handler和Message来完成消息机制,其实内部还有两大助手来共同完成消息传递。

Handler机制模型

消息机制主要包含:MessageQueueHandlerLooper这三大部分,以及Message

  • Message: 需要传递的消息,可以传递数据;
  • MessageQueue: 消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息MessageQueue.enqueueMessage和取走消息池的消息MessageQueue.next
  • Handler: 消息辅助类,主要功能向消息池发送各种消息事件Handler.sendMessage和处理相应消息事件Handler.handleMessage
  • Looper: 不断循环执行Looper.loop,从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

Handler机制架构

运行流程:在子线程执行完耗时操作,当Handler发送Message时,会调用MessageQueue.enqueueMessage,向消息队列中添加Message。当通过Looper.loop开启循环后,会不断从线程池中读取消息,即调用MessageQueue.next,然后调用目标Handler(即发送该消息的Handler)的dispatchMessage方法传递消息,然后返回到Handler所在线程,目标Handler收到消息,调用handleMessage方法,接收处理消息。
在这里插入图片描述

每个线程只能存在一个LooperLooper保存在ThreadLocal线程中。主线程(UI线程)已经创建了一个Looper,所以在主线程中不需要再创建Looper,但是在其他线程中需要创建Looper。每个线程可以有多个Handler,即一个Looper可以处理来自多个Handler的消息。Looper中维护一个MessageQueue,来维护消息队列,消息队列中的Message可以来自不同的Handler

在这里插入图片描述
Looper有一个MessageQueue消息队列,MessageQueue有一组待处理的MessageMessage中记录发送和处理消息的HandlerHandler中有LooperMessageQueue

Handler机制源码解析

ActivityThread

ActivityThread类是用来启动Android的,在main()函数中准备相关环境,创建并启动Looper循环。

主线程中不需要自己创建Looper,这是由于在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法。

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

    // Install selective syscall interception
    AndroidOs.install();

    // 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();

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    // Call per-process mainline module initialization.
    initializeMainlineModules();

    Process.setArgV0("<pre-initialized>");

    // 1. 把主线程和消息队列放进Looper中,同时把Looper放进ThreadLocal(每个线程绑定一个Looper)
    Looper.prepareMainLooper();

    // ....

    // 启动Looper循环,不断循环取出消息
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

Looper

Looper不断循环执行loop(),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

  1. 初始化Looper
public final class Looper {

    // sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    @UnsupportedAppUsage
    private static Looper sMainLooper;  // guarded by Looper.class

    @UnsupportedAppUsage
    final MessageQueue mQueue;
    final Thread mThread;

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

    /**
     * 创建Looper,并保存在ThreadLocal,不能重复创建Looper,只能创建一个。 
     */
    private static void prepare(boolean quitAllowed) {
        // 不能重复创建否则报错
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 4. 实例化自己,封装mQueue和主线程,把自己放入ThreadLocal中
        sThreadLocal.set(new Looper(quitAllowed));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. See also: {@link #prepare()}
     *
     * @deprecated The main looper for your application is created by the Android environment,
     *   so you should never need to call this function yourself.
     */
    @Deprecated
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

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

    private Looper(boolean quitAllowed) {
        // 2. 实例化MessageQueue
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

}
  1. 开启Looper
    /**
     * 5. 调用Looper.loop()方法
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        // 获取TLS存储的Looper对象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;
        // 获取Looper对象中的消息队列
        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();
        
        // 进入loop()主循环
        for (;;) {
            // 消息队列取出一条消息
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // 默认为null,可通过setMessageLogging()方法来指定输出,用于debug功能
            // 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);
            }

            // .....

            try {
                // 获取msg的目标Handler,然后用于分发Message
                msg.target.dispatchMessage(msg);
                
                // ....
            } catch (Exception exception) {
                // ...
            } finally {
                // ...
            }

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

            // 回收可能正在使用的消息
            msg.recycleUnchecked();
        }
    }

loop()进入循环模式,不断重复下面的操作,直到消息为空时退出循环:读取MessageQueue的下一条Message;把Message分发给相应的target

next()取出下一条消息时,队列中已经没有消息时,next()会无限循环,产生阻塞。等待MessageQueue中加入消息,然后重新唤醒。

Handler

消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage)。

  1. 创建Handler
public class Handler {

    @UnsupportedAppUsage
    final Looper mLooper;
    // 这里并没有实例化,指向Lopper的消息队列
    final MessageQueue mQueue;
    @UnsupportedAppUsage
    final Callback mCallback;
    final boolean mAsynchronous;
    @UnsupportedAppUsage
    IMessenger mMessenger;

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

}

构造函数:

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

    @Deprecated
    public Handler(@Nullable Callback callback) {
        this(callback, false);
    }

    @UnsupportedAppUsage
    public Handler(boolean async) {
        this(null, async);
    }

    /**
     * 第一种构造方法:给主线程调用,因为主线程已经调用Looper.prepareMainLooper()
     */
    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());
            }
        }

        // 获取主线程的Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }

        // Handler的mQueue指向Looper的mQueue
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }

    public Handler(@NonNull Looper looper, @Nullable Callback callback) {
        this(looper, callback, false);
    }

    /**
     * 第二种构造方法,给在子线程中创建Handler时使用,子线程要自主调用Looper.prepare()
     */
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

  1. 发送消息

发送消息有几种方式,但是归根结底都是调用了sendMessageAtTime()方法。在子线程中通过Handlerpost()方式或send()方式发送消息,最终都是调用了sendMessageAtTime()方法。

post方法:

    public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

    public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }

    public final boolean postAtTime(
            @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }

    public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }

    public final boolean postDelayed(Runnable r, int what, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
    }

    public final boolean postDelayed(
            @NonNull Runnable r, @Nullable Object token, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r, token), delayMillis);
    }

send方法:

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

    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

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

就连子线程中调用Activity中的runOnUiThread()更新UI,其实也是发送消息通知主线程更新UI,最终也会调用sendMessageAtTime()方法。

/**
 * 如果当前的线程不等于UI线程(主线程),就去调用Handler的post()方法,最终会调用sendMessageAtTime()方法。
 * 否则就直接调用Runnable对象的run()方法。
 */
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

sendMessageAtTime()

    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        // 其中mQueue是消息队列,从Looper中获取的
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        // 调用enqueueMessage方法
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        // 把自己(Handler)传入消息一并发送,因为Looper需要用Handler来执行dispatchMessage()
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 调用MessageQueue的enqueueMessage方法
        return queue.enqueueMessage(msg, uptimeMillis);
    }

可以看到sendMessageAtTime()方法的作用很简单,就是调用MessageQueueenqueueMessage()方法,往消息队列中添加一个消息。

在这里插入图片描述

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值