handler源码解析

handler源码分析

1.基本使用

handler:发送和接受消息

looper:用于轮询消息队列

MessageQueue:消息队列用于存储消息和管理消息

kotlin 复制代码
//UI线程
val handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.obj) {
                CODE_UPDATE -> {
                    //处理消息
                }
            }
        }
    }

	
    Thread {
        val message = Message.obtain()
        message.what = CODE_UPDATE


        //发送消息
        handler.sendMessage(message)


        //发送一条延时消息 
        handler.sendMessageDelayed(message,200)
    }.start()


	Thread{
		handler.post {
        	// 在UI线程执行的任务
    	}
	}

1.创建handler对象

2.使用post方法或者sendMessage方法

3.在handler所在的线程,进行消息处理

两种发送信息的方式,一种是发送Message,一种是post。

分别看下两种方式的源码处理

2.流程解析

2.1 handler创建

less 复制代码
//android.os.Handler
		
public Handler(@NonNull Looper looper) {
    this(looper, null, false);
}

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

class Handler{
    final Looper mLooper;
    final MessageQueue mQueue;
    ...
}

可以看到,在handler创建的时候,需要传入一个looper,而mQueue被Looper所持有

2.2 looper创建

在ActivityThread中的main方法中,已经为我们创建了looper

arduino 复制代码
android.app.ActivityThread
	
public static void main(String[] args) {

    ... 省略代码

    //初始化looper和MessageQueue
    Looper.prepareMainLooper();
    
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
     }

    ... 省略代码

    //轮询
    Looper.loop();

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

Looper.prepareMainLooper()进行了Looper和MessageQueue的创建

csharp 复制代码
android.os.Looper

public static void prepareMainLooper() {

    //不可退出
    prepare(false);

    synchronized (Looper.class) {
        //如果looper已经存在,则抛出异常
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}
		
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));
}

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

从代码可以看出,主要是通过Looper.prepare方法进行创建looper,先调用sThreadLocal.get()获取Looper,如果Looper已经存在,则抛出异常。如果不存在,则创建Looper并且设置到ThreadLocal中。再来看看ThreadLocal的具体实现

swift 复制代码
android.os.Looper

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
}
ini 复制代码
java.lang.ThreadLocal

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
 }

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
		
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null){
        map.set(this, value);
    }else{
        createMap(t, value);
    }
}

ThreadLocal的作用是为每个线程提供一个独立的变量副本,通过ThreadLocalMap来实现对每个线程的变量副本的存储和获取。获取到当前线程对应的ThreadLocalMap,static final修饰的threadLocal变量作为key,value则是looper实例,进行存储。由于key永远是同一个,再加Looper.prepare会先判断当前线程是否存在looper,所以Looper在每个线程中只会存在一个Looper

2.3 MessageQueue创建

ini 复制代码
android.os.Looper

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

在looper的构造函数中,创建了MessageQueue,这个时候handler和looper,messagequeue就绑定在一起了。

2.4 handler.sendMessage

less 复制代码
android.os.Handler

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

public final boolean post(@NonNull Runnable r) {
    return sendMessageDelayed(getPostMessage(r), 0);
}
		
    //post 将runnable设置为msg的callback
private static Message getPostMessage(Runnable r) {
        	Message m = Message.obtain();
        	m.callback = r;
        	return m;
    	}

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

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

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

通过上面的代码可以看出,无论是sendMessage还是post都会走到sendMessageDelayed,在走到sendMessageAtTime方法,uptimeMillis则是一个具体的时间点,最后走到了enqueueMessage方法,msg.target = this,指向了当前handler。最后由queue.enqueueMessage进行处理。在一开始创建handler的时候,已经看到了mQueue是MessageQueue。接下来看MessageQueue是怎么处理这个消息的

ini 复制代码
android.os.MessageQueue

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
		
    //加锁
    synchronized (this) {
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
			
        //Looper.myLooper().quit(); 应用退出的时候才会被标记为true
        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) {
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            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;
            }
        }
        
        //唤醒
        if (needWake) {
            nativeWake(mPtr);
        }
            
        return true;
    }

插入队列这里进行了加锁,保证了线程安全。从代码看出这个队列是优先级队列,按照msg的when进行排序。当头节点为null或者头节点的when大于msg的when时,msg作为头节点。如果msg的when大于头节点,轮询将msg插入到合适的位置。

2.5 Looper.loop

已经将msg插入到messagequeue中,接下来看看loop是怎么处理的。

java 复制代码
android.os.Looper

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

    for (;;) {
        if (!loopOnce(me, ident, thresholdOverride)) {
            return;
            }
        }
    }
}


private static boolean loopOnce(final Looper me,final long ident, final int thresholdOverride) {
    //取出队列中的消息
    Message msg = me.mQueue.next(); // might block
    if (msg == null) {
        return false;
    }
		
    ...省略代码
    
    //msg.target就是handler
     msg.target.dispatchMessage(msg);

    ...省略代码

    msg.recycleUnchecked();

    return true;
}
ini 复制代码
android.os.MessageQueue


Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        //阻塞
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    //计算休眠的时间
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 获取消息并返回
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // 没有消息 一直阻塞
                nextPollTimeoutMillis = -1;
            }

            if (mQuitting) {
                dispose();
                return null;
            }

           
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        pendingIdleHandlerCount = 0;

        nextPollTimeoutMillis = 0;
    }
}

在循环中,程序不断地从消息队列中获取消息。如果成功获取到消息,程序会判断当前时间是否小于消息的触发时间(msg.when)。如果是,会计算出下一次轮询超时的时间(nextPollTimeoutMillis),然后通过调用nativePollOnce方法来进行等待,该方法底层会调用Linux的epoll方法。

如果当前消息队列中没有任何消息,程序将会无限等待,直到有新的消息到达。这个过程会不断重复,保证程序能够及时处理消息

msg.target是handler,在取出msg后,最终会调用到handler的dispatchMessage方法。接下来又会执行msg.recycleUnchecked()方法。

ini 复制代码
void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

这里将msg的标记进行置空,释放所有资源,在判断当前队列的msg数量是否小于MAX_POOL_SIZE(50),如果小于则插入到表头。

2.6 Handler.dispatchMessage

typescript 复制代码
public void dispatchMessage(@NonNull Message msg) {
    //post runnable设置msg的callback
    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();
}

如果是post过来的消息,一开始传入的时候已经将runnable设为msg的callback,这个时候直接执行run函数,否则由handler的callback回调处理。

相关推荐
帅次8 分钟前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
枯骨成佛1 小时前
Android中Crash Debug技巧
android
kim56596 小时前
android studio 更改gradle版本方法(备忘)
android·ide·gradle·android studio
咸芝麻鱼6 小时前
Android Studio | 最新版本配置要求高,JDK运行环境不适配,导致无法启动App
android·ide·android studio
无所谓จุ๊บ6 小时前
Android Studio使用c++编写
android·c++
csucoderlee7 小时前
Android Studio的新界面New UI,怎么切换回老界面
android·ui·android studio
kim56597 小时前
各版本android studio下载地址
android·ide·android studio
饮啦冰美式7 小时前
Android Studio 将项目打包成apk文件
android·ide·android studio
夜色。7 小时前
Unity6 + Android Studio 开发环境搭建【备忘】
android·unity·android studio
ROCKY_8179 小时前
AndroidStudio-滚动视图ScrollView
android