Android消息机制之Handler的深入理解

本文详细探讨了Android的Handler机制,从BlockingRunnable到消息传递和处理,再到Looper和MessageQueue的关系。一个Thread可以对应多个Handler,MessagePool容量为50。文章通过分析Looper的结构和Message的分发流程,阐述了Handler如何在Java层与Native层交互。

上周老大让我主持了一个团队技术培训的会议,会议的内容是Handler技术的整体使用流程,包括从Java端到Native端的分析。借此机会,写成一篇文章记录一下成果。若有不足之处,希望大家可以指出,欢迎互相讨论,谢谢。

Java层中的消息生成是从用户创建的Message对象而来的,它是一个由Runnable封装过的对象。或者从Message Pool调用getsMessage派生得来的,而Message Pool是指消息类Message循环队列,这个队列可以容纳的最大Message数量是MAX_POOL_SIZE=50。

这里写图片描述

既然说到了Message,那么就有必要提一下Looper,Handler,MessageQuene和Message之间的关系了。

这里写图片描述

总结如下:

一个Thread仅对应一个Looper;而一个Looper对象只对应一个MessageQueue;另外,一个MessageQueue对应多个Messsage;一个Message只对应一个Handler

所以我们得出的结论是:一个Thread可以对应多个Handler

MessagePool是一个循环队列,当Message的数量超过50个的时候,则会回到队头并请空该Message,为了下一次复用。

BlockingRunnable

先上代码:

private static final class BlockingRunnable implements Runnable {
    private final Runnable mTask;
    private boolean mDone;

    public BlockingRunnable(Runnable task) {
        mTask = task;
    }

    @Override
    public void run() {
        try {
            mTask.run();
        } finally {
            synchronized (this) {
                mDone = true;
                notifyAll();
            }
        }
    }

    public boolean postAndWait(Handler handler, long timeout) {
        if (!handler.post(this)) {
            return false;
        }

        synchronized (this) {
            if (timeout > 0) {
                final long expirationTime = SystemClock.uptimeMillis() + timeout;
                while (!mDone) {
                    long delay = expirationTime - SystemClock.uptimeMillis();
                    if (delay <= 0) {
                        return false; // timeout
                    }
                    try {
                        wait(delay);
                    } catch (InterruptedException ex) {
                    }
                }
            } else {
                while (!mDone) {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }
        return true;
    }
}

BlockingRunnable是在“包装器”构造函数中传递的Runnable 的任务,而对BlockingRunnable的postAndWait调用执行以下操作:

  1. 锁定交付BlockingRunnable的线程
  2. 如果交付BlockingRunnable失败,则返回false

消息传递和处理

获取消息后,会通过Handler中sendMessageAtTime方法调用MessageQueue的enqueueMessage,并将消息传递给MessageQueue。

Handler的创建

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 that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

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

主要完成的任务:

  1. 获取当前的Handler类
  2. 如果声明的程序是匿名内部类,成员类或局部类,并且处理程序的修饰符不是静态的。那么会打印出日志,提示可能会发生内存泄漏。

Looper

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

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

参数介绍:

  1. sMainLooper:Looper使用主线程
  2. mQueue:与Looper关联的MessageQueue
  3. mThread:与Looper关联的线程
  4. sThreadLocal:线程局部变量key

由此我们可以看到一个线程对应一个Looper,一个Looper对应一个MessageQueue

消息的分发

public static void loop() {
    ……

    for (;;) {
        Message msg = queue.next(); // might block

        ……

        try {
            msg.target.dispatchMessage(msg);
        } finally {
            ……
        }

        ……

        msg.recycleUnchecked();
    }
}
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

在为其他线程创建Looper后,调用loop()将执行以下操作:

  1. 在MessageQueue中循环获取消息
  2. 将消息通过Handler的dispatchMessage方法分配给相应的Handler
  3. 清空消息,并将其回收到Message Pool中供下次使用

在Handler的dispatchMessage中:

  1. 如果Message设置了回调,则将Message传递给Message的回调处理
  2. 如果Handler设置了回调,则将Message先交给Handler的回调方法处理。否则,将消息交给Handler的handleMessage处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值