Android 消息机制--Handle

一、handle的基本用法
Handler负责我们的消息发送和处理,一般我们创建一个Handler对象,只需要重写它的handleMessage()方法进行处理我们的业务逻辑。

 private Handler handler = new Handler(){
     @Override
     public void handleMessage(Message msg) {
     }
 };
 handler.sendEmptyMessage(0);

二、常用的发送消息的方法及其实现

public final boolean sendEmptyMessage(int what) 
//发送空的消息
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
 //在指定时间点发送空消息
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
//延迟指定时间发送消息
public final boolean sendMessage(Message msg)
//发送消息Message
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
//在指定时间发送消息Message
public final boolean sendMessageDelayed(Message msg, long delayMillis)
//延迟指定时间发送消息Message

三、调用流程分析
1、常用典型示例

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        // 1. 初始化 Looper 对象,其内部会创建消息队列。
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
            // 4. 处理消息队列中的消息。
            }
        };
        // 2. 开启消息循环,会从消息队列中取出消息,没有消息时阻塞等待新消息的到来。
        Looper.loop();
    }

    // 3. 发送消息
    mHandler.sendEmptyMessage(0);
}

2、Looper.prepare() 的调用流程
初始化 Looper 对象,其内部会创建消息队列。

//注意为静态final变量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
       prepare(true);
   }
   
private static void prepare(boolean quitAllowed) {
    //一个Thread只能关联一个Looper对象
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

//(每个Looper对象的)消息队列,也就是说每个Looper对象都持有自己的消息队列
 final MessageQueue mQueue;
//(每个Looper线程关联的)当前线程
final Thread mThread;
private Looper(boolean quitAllowed) {
	    //初始化当前Looper对象的消息队列
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();//获取当前线程
    }	

注:
1.每个Looper对象都有自己的消息队列MessageQueue
2.每个Looper对象都和当前线程相关联。

3、ThreadLocal方法

static final ThreadLocal<T> sThreadLocal = new ThreadLocal<T>();
sThreadLocal.set()
sThreadLocal.get()

//set 方法
public void set(T value) {
    //(1)获取当前线程(调用者线程)
    Thread t = Thread.currentThread();
    //(2)以当前线程作为key值,去查找对应的线程变量,找到对应的map
    ThreadLocalMap map = getMap(t);
    //(3)如果map不为null,就直接添加本地变量,key为当前线程,值为添加的本地变量值
    if (map != null)
        map.set(this, value);
    //(4)如果map为null,说明首次添加,需要首先创建出对应的map
    else
        createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals; 
//获取线程自己的变量threadLocals,并绑定到当前调用线程的成员变量threadLocals上
}
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
public T get() {
    //(1)获取当前线程
    Thread t = Thread.currentThread();
    //(2)获取当前线程的threadLocals变量
    ThreadLocalMap map = getMap(t);
    //(3)如果threadLocals变量不为null,就可以在map中查找到本地变量的值
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    //(4)执行到此处,threadLocals为null,调用该更改初始化当前线程的threadLocals变量
    return setInitialValue();
}

private T setInitialValue() {
    //protected T initialValue() {return null;}
    T value = initialValue();
    //获取当前线程
    Thread t = Thread.currentThread();
    //以当前线程作为key值,去查找对应的线程变量,找到对应的map
    ThreadLocalMap map = getMap(t);
    //如果map不为null,就直接添加本地变量,key为当前线程,值为添加的本地变量值
    if (map != null)
        map.set(this, value);
    //如果map为null,说明首次添加,需要首先创建出对应的map
    else
        createMap(t, value);
    return value;
}

public void remove() {
    //获取当前线程绑定的threadLocals
     ThreadLocalMap m = getMap(Thread.currentThread());
     //如果map不为null,就移除当前线程中指定ThreadLocal实例的本地变量
     if (m != null)
         m.remove(this);
 }

4、Looper.loop()的调用流程

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {
    // 获取当前线程的 Looper 对象,获取失败时抛出异常。
    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;

    // 省略无关代码

    // 开启一个无限循环来监听消息队列的情况
    for (;;) {
        // 获取消息队列中的消息对象,如果没有消息对象就阻塞等待。
        Message msg = queue.next(); // might block
        if (msg == null) {
            // 消息队列正在退出时就终止监听并退出循环
            return;
        }

        // 省略无关代码

        try {
            // 分发消息,把消息发送合适的处理对象。
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        // 省略无关代码

        // 回收消息对象,放入消息缓存池中以待后续复用。
        msg.recycleUnchecked();
    }
}

myLooper()
//获取当前线程关联的Looper对象
public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
dispatchMessage
public void dispatchMessage(Message msg) {
       //如果创建的msg,设置了callback这个Runnable
       if (msg.callback != null) {
           //执行callback方法,其实是执行run方法
           handleCallback(msg);
       } else {//如果创建Handler的时候创建了Callback对象
           if (mCallback != null) {
               //执行callback的handleMessage方法
               if (mCallback.handleMessage(msg)) {
                   return;
               }
           }
           //让handler自己来处理msg
           handleMessage(msg);
       }
   }

private static void handleCallback(Message message) 
{
       //只是简单的调用了Runnable的run方法
       message.callback.run();
}
//简单的接口,提供了一个handleMessage方法来处理消息
public interface Callback 
{
       //返回一个boolean值
       public boolean handleMessage(Message msg);
}
/**
 * Subclasses must implement this to receive messages.
 */
// Handler 的处理消息回调,子类需要实现。
public void handleMessage(Message msg) {
}

5、mHandler.sendEmptyMessage(0)调用流程介绍

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

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

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

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

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;
}
/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is 
 * attached. 
 *  
 * @param r The Runnable that will be executed.
 * 
 * @return Returns true if the Runnable was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean post(Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    // 把 Runnable 对象封装成 Message 并设置 callback,
    // 这个 callback 会在后面消息的分发处理中起到作用。
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    // 把延迟时间转换为绝对时间,方便后续执行。
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    // 消息队列,即通过 Looper.prepare() 创建的消息队列。
    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);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    // 设置消息队列的目标,用于后续的消息分发过程。
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    // 消息对象入队
    return queue.enqueueMessage(msg, uptimeMillis);
}

注:
消息的分发是有一定优先顺序的:
首先会考虑交给Message.callback来处理,如果是通过post系列函数发送的消息会走到这里进行处理,而通过send系列函数发送的消息默认是没有这个回调接口的;
如果Message.callback不存在就考虑交给Handler.callback来处理,在处理过程中可以通过返回值拦截消息;
如果Handler.callback不存在或者存在但是在处理消息过程中没有进行拦截,就会交给Handler.handleMessage来处理,这个接口需要子类实现,也是在实际工作中最常用的处理消息的地方。

四、额外
1、sendMessage 系列函数

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

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

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

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

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

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

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

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

2、Message的复用机制
Message的创建方式:虽然Message有公有构造函数,但是建议使用其提供的obtain系列函数来获取Message对象,这种创建方式会重复利用缓存池中的对象而不是直接创建新的对象,从而避免在内存中创建太多对象,避免可能的性能问题。

/**
 * Return a new Message instance from the global pool. Allows us to
 * avoid allocating new objects in many cases.
 */
public static Message obtain() {
    synchronized (sPoolSync) {
        // 缓存池中存在可用对象时去缓存池获取 Message 对象。
        if (sPool != null) {
            // 获取缓存中的对象,并把缓存池指针后移。 
            Message m = sPool;
            sPool = m.next;

            m.next = null;
            // 清除标志位
            m.flags = 0; // clear in-use flag
            // 更新当前缓存池大小
            sPoolSize--;
            return m;
        }
    }
    // 缓存池中没有可用对象时直接创建一个新的 Message 对象。
    return new Message();
}
注:obtain函数是从缓存池中获取Message对象,那缓存池中的对象是什么时候被添加进去的呢?
既然缓存池中的对象都是一些可以被重复使用的对象,很明显是在Message对象不再被需要的时候,
即从MessageQueue中取出并分发给Handler的时候,被添加到缓存中的,使用的是recycleUnchecked函数
/**
 * Recycles a Message that may be in-use.
 * Used internally by the MessageQueue and Looper when disposing of queued Messages.
 */
void recycleUnchecked() {
    // 设置标志位为“使用中”,在从缓存中取出时会清除这个标志位。
    flags = FLAG_IN_USE;
    // Message 对象中的信息都不再有意义,在放入缓存池前直接清空。
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        // 缓存池中只缓存一定数量的 Message 对象,默认是 50 个。
        if (sPoolSize < MAX_POOL_SIZE) {
            // 把对象放在缓存池的链表首部。 
            next = sPool;
            sPool = this;
            // 及时更新缓存池大小。
            sPoolSize++;
        }
    }
}
注:removeCallbacksAndMessages时调用recycleUnchecked
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;
}
public void copyFrom(Message o) {
	this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
	this.what = o.what;
	this.arg1 = o.arg1;
	this.arg2 = o.arg2;
	this.obj = o.obj;
	this.replyTo = o.replyTo;
	this.sendingUid = o.sendingUid;

	if (o.data != null) {
		this.data = (Bundle) o.data.clone();
	} else {
		this.data = null;
}

public final boolean sendMessageAtFrontOfQueue(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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值