handler源码学习(1) — Handler

5 篇文章 0 订阅
4 篇文章 0 订阅

马上年底了,年初制定的计划好多都没完成。这一年写了很多东西。但是又都感觉深度不够,所以没有发出来。最近整理了下,准备慢慢发出来。进入正文。

Handler是面试必问系列问题之一。本系列将从初学者的视角分析面试中常见的问题。

handler源码学习(1) — Handler
handler源码学习(2) — Message
handler源码学习(3) — Looper
handler源码学习(4) — MessageQueue

1. 创建Handler

1.1 首先看构造方法
    //1
    public Handler() {
    this(null, false);
    }

    //2
    public Handler(@Nullable Callback callback){
        this(callback, false);
    }
    //3
    public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }
    //4
    public Handler(@NonNull Looper looper, @Nullable Callback callback) {
        this(looper, callback, false);
    }
    //5
    @UnsupportedAppUsage
    public Handler(boolean async) {
        this(null, async);
    }
    //6
    public Handler(@Nullable Callback callback, boolean async) {
        //FIND_POTENTIAL_LEAKS是一个值为false的常量。按道理是不可能为true,不知道什么时候会变为true
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            //如果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()");
        }
        //赋值操作
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    //7
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    

可以看到一共7个构造方法,我都在注释上加了编号,可以发现带looper的最后都是调用了方法7,不带looper的都是调用了方法6。这里都加了具体的注释。只对这几个参数作用说明。

looper:为handler指定looper的线程

mQueue:looper的队列

mCallback:handler处理的回调

mAsynchronous:是否发送异步消息。后面同步屏障会讲。

1.2 静态方法创建
    public static Handler createAsync(@NonNull Looper looper) {
        if (looper == null) throw new NullPointerException("looper must not be null");
        return new Handler(looper, null, true);
    }
    
    public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
        if (looper == null) throw new NullPointerException("looper must not be null");
        if (callback == null) throw new NullPointerException("callback must not be null");
        return new Handler(looper, callback, true);
    }
    
    /** @hide */
    @UnsupportedAppUsage
    @NonNull
    public static Handler getMain() {
        if (MAIN_THREAD_HANDLER == null) {
            MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
        }
        return MAIN_THREAD_HANDLER;
    }

    /** @hide */
    @NonNull
    public static Handler mainIfNull(@Nullable Handler handler) {
        return handler == null ? getMain() : handler;
    }

前两个都是创建异步hanlder,后边两个是获取main线程的handler。

2.obtainMessage 创建消息

    public final Message obtainMessage(){
        return Message.obtain(this);
    }
    
    public final Message obtainMessage(int what){
        return Message.obtain(this, what);
    }
    
    public final Message obtainMessage(int what, @Nullable Object obj) {
        return Message.obtain(this, what, obj);
    }
    
    public final Message obtainMessage(int what, int arg1, int arg2){
        return Message.obtain(this, what, arg1, arg2);
    }
    
    public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
        return Message.obtain(this, what, arg1, arg2, obj);
    }

都是调用的Message的静态方法创建一个消息。这和我们直接new Message()有什么区别呢?。先跳过,后续讲message的时候具体分析。

3.发送消息

sendMessagexxx和postMessagexxx,因为post最后要调用
sendMessagexxx,所以我们先看sendMessagexxx

3.1 send消息

再看发送消息,这里我们加上编号。

  • 1.sendMessage(Message msg)
  • 2.sendEmptyMessage(int what)
  • 3.sendEmptyMessageDelayed(int what, long delayMillis)
  • 4.sendEmptyMessageAtTime(int what, long uptimeMillis)
  • 5.sendMessageDelayed(Message msg, long delayMillis)
  • 6.sendMessageAtTime(Message msg, long uptimeMillis)
  • 7.sendMessageAtFrontOfQueue(Message msg)

通过观察我们可以看到他们的关系

  • 1–>5–>6
  • 2–>3–>5–>6
  • 4–>6
  • 6–>enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
  • 7–>enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)

这个有2个知识点。

  • 我们看到最后都是调用的1,2,3,4,5最后都是调用sendMessageAtTime这个方法。那么发送延时消息是怎么计时的呢?看下源码
    public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

注意这里SystemClock.uptimeMillis() + delayMillis。SystemClock.uptimeMillis()这个方法返回的官方注解Returns milliseconds since boot, not counting time spent in deep sleep.。个人理解手机启动后未休眠状态的时间。Android 7.0之后手机息屏太久会进入休眠。可以看到会计算出延时后的时间,然后进行入队列。

  • sendMessageAtFrontOfQueue如何添加到队头的?
    public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg){
        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, 0);
    }
    
    public boolean sendMessageAtTime(@NonNull 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);
    }

可以看到sendMessageAtFrontOfQueue和sendMessageAtTime的区别就是在enqueueMessage的第三个参数不同。实时上,messageQueue入队列就是根据这个时间入队列的。

3.1.1 入队列,进入消息池

看名字就是消息入队列了。看下源码

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //target是Message的成员变量
        msg.target = this;
        if (mAsynchronous) {
            //是否异步,同步屏障再讲这里
            msg.setAsynchronous(true);
        }
        //MessageQueue执行入队列操作
        return queue.enqueueMessage(msg, uptimeMillis);
    }

MessageQueue的enqueueMessage(msg, uptimeMillis)等我们看MessageQueue时再具体细讲。

3.2 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);
    }
    
    public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
        return sendMessageAtFrontOfQueue(getPostMessage(r));
    }

可以看到分别调用了sendMessageAtTime(@NonNull Message msg, long uptimeMillis)和sendMessageDelayed(@NonNull Message msg, long delayMillis)。和sendMessage唯一不同的地方就是这里的message,这里会调用getPostMessage(Runnable r)和getPostMessage(Runnable r, Object token)。看下其中的一个源码。

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

我们再看下dispatchMessage

    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    private static void handleCallback(Message message) {
        message.callback.run();
    }

明白了吗?如果msg.callBack!=null,则会调用message.callback.run()。我们postMessage,这里会帮我给msg.callback赋值为我们传递的runnable。当分发消息时,就调用这个runnable.run。这就是为什么我们post消息没有调用runnable.run()却可以直接在runnable的run里面的逻辑却可以正常运行。

4.移除回调或者message

    public final void removeCallbacks(@NonNull Runnable r) {
        mQueue.removeMessages(this, r, null);
    }
    
    public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
        mQueue.removeMessages(this, r, token);
    }
    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }
    public final void removeMessages(int what, @Nullable Object object) {
        mQueue.removeMessages(this, what, object);
    }
    public final void removeCallbacksAndMessages(@Nullable Object token){
        mQueue.removeCallbacksAndMessages(this, token);
    }

MessageQueue具体分析。

5.总结

纵观Handler一共做了一下几件事

  • 创建Handler
  • 创建消息
  • 发送消息
  • 移除回调,或者消息

解决了疑问:

  • 有哪些主要方法
  • 如何发送延迟消息(如何计算消息触发时间的)
  • sendMessageAtFrontOfQueue如何添加到消息队头
  • 为什么我们post消息可以直接在runnable的run里处理业务逻辑

同时留下几个问题:

  • 如何实现同步屏障
  • obtainMessage()和new Message的区别
  • queue.enqueueMessage(msg, uptimeMillis);做了什么
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值