发现无论是Windows还是Android,它们都是利用消息机制来运行一个程序,使得程序能够持久的运行下去,那它们之间都有共同的特点,都属于CS端

那么为了更好的深入理解android的消息机制,我打算手写一个Java版的Handler来模拟Android程序运行

1.首先我创建了一些空白类,其中Main类是我们程序的入口

【android】手写一套Java的Handler程序,深入理解Android消息机制_第1张图片

2.接着我们开始手写Looper

在Looper中我们知道有两个非常重要的方法prepare()和loop(),在sdk中找到相关源码,提取关键,形成一份精简的代码

/** * Created by ccwant on 2019-01-10. */public class Looper {    private static final String TAG = "Looper";    private static Looper sMainLooper;  // guarded by Looper.class    static final ThreadLocal sThreadLocal = new ThreadLocal();    final MessageQueue mQueue;    final Thread mThread;    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }    /**     * 将当前线程初始化为循环器,并将其标记为     * 应用程序的主环。应用程序的主循环器     * 由Android环境创建,因此您不应该需要     * 自行调用此函数。另请参见:@link prepare()     */    public static void prepareMainLooper() {        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }    public static Looper getMainLooper() {        synchronized (Looper.class) {            return sMainLooper;        }    }    public static void prepare() {        prepare(true);    }    private static void prepare(boolean quitAllowed) {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        Log.d(TAG,"创建了一个新的Looper");        sThreadLocal.set(new Looper(quitAllowed));    }    public static void loop() {        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) {                // No message indicates that the message queue is quitting.                return;            }            msg.target.dispatchMessage(msg);            msg.recycleUnchecked();        }    }    public static Looper myLooper() {        return sThreadLocal.get();    }}

3.手写MeesageQueue

同样,在MeesageQueue中也有两个非常重要的方法next()和enqueueMessage(),分别用于读取消息和插入新消息

import java.util.ArrayList;/** * Created by ccwant on 2019-01-10. */public class MessageQueue {    private static final String TAG = "MessageQueue";    // True if the message queue can be quit.    private final boolean mQuitAllowed;    Message mMessages;    private final ArrayList mIdleHandlers = new ArrayList();    private IdleHandler[] mPendingIdleHandlers;    private boolean mQuiting;    // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.    private boolean mBlocked;    MessageQueue(boolean quitAllowed) {        Log.d(TAG,"初始化消息队列");        mQuitAllowed = quitAllowed;    }    Message next() {        int pendingIdleHandlerCount = -1; // -1 only during first iteration        int nextPollTimeoutMillis = 0;        for (; ; ) {            synchronized (this) {                // Try to retrieve the next message.  Return if found.                final long now = System.currentTimeMillis();                final Message msg = mMessages;                if (msg != null) {                    final long when = msg.when;                    if (now >= when) {                        mBlocked = false;                        mMessages = msg.next;                        msg.next = null;                        Log.d(TAG, "Returning message: " + msg);                        msg.markInUse();                        return msg;                    } else {                        nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);                    }                } else {                    nextPollTimeoutMillis = -1;                }                // If first time, then get the number of idlers to run.                if (pendingIdleHandlerCount < 0) {                    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);            }            // Run the idle handlers.            // We only ever reach this code block during the first iteration.            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.d("MessageQueue", "IdleHandler threw exception");                }                if (!keep) {                    synchronized (this) {                        mIdleHandlers.remove(idler);                    }                }            }            // Reset the idle handler count to 0 so we do not run them again.            pendingIdleHandlerCount = 0;            // While calling an idle handler, a new message could have been delivered            // so go back and look again for a pending message without waiting.            nextPollTimeoutMillis = 0;        }    }    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.");        }        final boolean needWake;        synchronized (this) {            if (mQuiting) {                RuntimeException e = new RuntimeException(                        msg.target + " sending message to a Handler on a dead thread");                Log.w("MessageQueue", e.getMessage());                return false;            } else if (msg.target == null) {                mQuiting = true;            }            msg.when = when;            Log.d("MessageQueue", "Enqueing: " + msg);            Message p = mMessages;            if (p == null || when == 0 || when < p.when) {                msg.next = p;                mMessages = msg;                needWake = mBlocked; // new head, might need to wake up            } else {                Message prev = null;                while (p != null && p.when <= when) {                    prev = p;                    p = p.next;                }                msg.next = prev.next;                prev.next = msg;                needWake = false; // still waiting on head, no need to wake up            }        }        if (needWake) {            //nativeWake(mPtr);        }        return true;    }    private void dispose() {    }    /**     * 用于发现线程何时阻塞的回调接口     * 等待更多消息     */    public static interface IdleHandler {        /**         * 当消息队列中的消息用完时调用,现在将         * 等待更多信息。返回true以保持空闲处理程序处于活动状态,返回false         * 将其移除。如果仍有消息,则可以调用此函数         * 在队列中挂起,但它们都计划调度         * 在当前时间之后。         */        boolean queueIdle();    }}

4.手写Message对象

这里Message是一个实体类,我们通常使用它来传递消息对象,在这个地方我们同样精简化

import java.io.Serializable;/** * Created by ccwant on 2019-01-10. */public class Message implements Serializable {    public int what;    public Object obj;    public int sendingUid = -1;    /**     * 如果正在使用set message。     * 此标志在消息排队时设置,在消息排队时保持设置状态。     * 交付后再回收。该标志只被清除     * 当创建或获取新消息时,因为这是唯一一次     * 允许应用程序修改消息的内容。     * 试图排队或回收已在使用的邮件是一个错误。     */    static final int FLAG_IN_USE = 1 << 0;    /**     * 如果设置消息是异步的     */    static final int FLAG_ASYNCHRONOUS = 1 << 1;    /**     * 在CopyFrom方法中要清除的标志     */    static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;        int flags;    long when;    Handler target;    Runnable callback;    Message next;    private static final Object sPoolSync = new Object();    private static Message sPool;    private static int sPoolSize = 0;    private static final int MAX_POOL_SIZE = 50;    private static boolean gCheckRecycle = true;    /**     * 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) {            if (sPool != null) {                Message m = sPool;                sPool = m.next;                m.next = null;                m.flags = 0; // clear in-use flag                sPoolSize--;                return m;            }        }        return new Message();    }    public boolean isAsynchronous() {        return (flags & FLAG_ASYNCHRONOUS) != 0;    }    void markInUse() {        flags |= FLAG_IN_USE;    }    public void setAsynchronous(boolean async) {        if (async) {            flags |= FLAG_ASYNCHRONOUS;        } else {            flags &= ~FLAG_ASYNCHRONOUS;        }    }    /*package*/ boolean isInUse() {        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);    }    public void recycle() {        if (isInUse()) {            if (gCheckRecycle) {                throw new IllegalStateException("This message cannot be recycled because it "                        + "is still in use.");            }            return;        }        recycleUnchecked();    }    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;        obj = null;        //replyTo = null;        sendingUid = -1;        when = 0;        target = null;        callback = null;        //data = null;        synchronized (sPoolSync) {            if (sPoolSize < MAX_POOL_SIZE) {                next = sPool;                sPool = this;                sPoolSize++;            }        }    }    @Override    public String toString() {        return "Message{" +                "what=" + what +                ", obj=" + obj +                '}';    }}

5.手写Handler

精简Handler,提取关键方法sendMessage()

import java.lang.reflect.Modifier;/** * Created by ccwant on 2019-01-10. */public class Handler {    private static final boolean FIND_POTENTIAL_LEAKS = false;    private static final String TAG = "Handler";    private static Handler MAIN_THREAD_HANDLER = null;    final Looper mLooper;    final MessageQueue mQueue;    final Callback mCallback;    final boolean mAsynchronous;    public Handler() {        this(null, false);    }    public Handler(Callback callback) {        this(callback, false);    }    public Handler(Looper looper) {        this(looper, null, false);    }    public Handler(boolean async) {        this(null, async);    }    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) {                System.out.println("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 Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;    }    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, System.currentTimeMillis() +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.e(TAG,e.getMessage());            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);    }    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }    public void handleMessage(Message msg) {    }    private static void handleCallback(Message message) {        message.callback.run();    }    public interface Callback {        public boolean handleMessage(Message msg);    }}

6.到这里基本框架已经完成,紧接着我们模拟一下Android程序的运行

import com.ccwant.sys.Handler;import com.ccwant.sys.Log;import com.ccwant.sys.Looper;import com.ccwant.sys.Message;public class Main {    private static final String TAG = "Main";    public static void main(String[] args) {        Log.d(TAG, "主线程:" + Thread.currentThread().getName());        Looper.prepareMainLooper();        new Application().main();        Looper.loop();    }    private static class Application{        private static final String TAG = "Application";        public void main(){            Log.d(TAG, "Application create.");            startActivity();        }        private void startActivity(){            Activity activity = new Activity();            activity.onCreate();        }    }    private static class Activity{        private static final String TAG = "Activity";        Handler mHandler = new Handler(new Handler.Callback() {            @Override            public boolean handleMessage(Message msg) {                Log.d(TAG, "当前线程:" + Thread.currentThread().getName());                Log.d(TAG, "拦截消息:" + msg.obj);                return false;            }        });        public void onCreate(){            Log.d(TAG, "onCreate");            sendTest();        }        private void sendTest(){            new Thread(new Runnable() {                @Override                public void run() {                    //Looper.prepare();                    for (int i = 0; i < 2; i++) {                        Log.d(TAG, "-----------");                        Message msg = new Message();                        msg.obj = "123";                        msg.what = 1;                        Log.d(TAG, "准备发送:" +msg+" 当前线程:"+Thread.currentThread().getName());                        mHandler.sendMessage(msg);                        try {                            Thread.sleep(2000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                }            }).start();        }    }}

我们想一下,Android中我们知道有个主线程,UI的绘制全部是在主线程中运行,如果主线程结束,那么程序也就停止了。

这个主线程究竟是怎么运行起来的?

在这里,Looper起到了重大的作用,在Looper中的loop()方法,通过无限循环不断的读取消息,分发消息,从而保证程序的正常运行

讲到这里,我又翻了一下Android源码,在android.app.ActivityThread类中找到了入口main方法

【android】手写一套Java的Handler程序,深入理解Android消息机制_第2张图片

估计说到这里,有人会问:loop()的无限循环岂不是特别耗CPU资源?

其实不然,这里就涉及到Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源

还有人可能会问:Activity的生命周期是怎么实现在死循环体外能够执行起来的?

ActivityThread的内部类H继承于Handler,通过handler消息机制,简单说Handler机制用于同一个进程的线程间通信。

Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施:

在H.handleMessage(msg)方法中,根据接收到不同的msg,执行相应的生命周期。    

比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终会通过反射机制,创建Activity实例,然后再执行Activity.onCreate()等方法;    再比如收到msg=H.PAUSE_ACTIVITY,则调用ActivityThread.handlePauseActivity()方法,最终会执行Activity.onPause()等方法。

【android】手写一套Java的Handler程序,深入理解Android消息机制_第3张图片

上述过程,我只挑核心逻辑讲,真正该过程远比这复杂。主线程的消息又是哪来的呢?

当然是App进程中的其他线程通过Handler发送给主线程,请看接下来的内容:

最后,从进程与线程间通信的角度,通过一张图加深大家对App运行过程的理解:

【android】手写一套Java的Handler程序,深入理解Android消息机制_第4张图片

system_server进程是系统进程,java framework框架的核心载体,里面运行了大量的系统服务,比如这里提供ApplicationThreadProxy(简称ATP),ActivityManagerService(简称AMS),这个两个服务都运行在system_server进程的不同线程中,由于ATP和AMS都是基于IBinder接口,都是binder线程,binder线程的创建与销毁都是由binder驱动来决定的。

App进程则是我们常说的应用程序,主线程主要负责Activity/Service等组件的生命周期以及UI相关操作都运行在这个线程; 另外,每个App进程中至少会有两个binder线程 ApplicationThread(简称AT)和ActivityManagerProxy(简称AMP),除了图中画的线程,其中还有很多线程,比如signal catcher线程等,这里就不一一列举。

Binder用于不同进程之间通信,由一个进程的Binder客户端向另一个进程的服务端发送事务,比如图中线程2向线程4发送事务;而handler用于同一个进程中不同线程的通信,比如图中线程4向主线程发送消息。

结合图说说Activity生命周期,比如暂停Activity,流程如下:

1.线程1的AMS中调用线程2的ATP;(由于同一个进程的线程间资源共享,可以相互直接调用,但需要注意多线程并发问题)

2.线程2通过binder传输到App进程的线程4;

3.线程4通过handler消息机制,将暂停Activity的消息发送给主线程;

4.主线程在looper.loop()中循环遍历消息,当收到暂停Activity的消息时,便将消息分发给ActivityThread.H.handleMessage()方法,再经过方法的调用,最后便会调用到Activity.onPause(),当onPause()处理完后,继续循环loop下去。

更多相关文章

  1. 第十一章、Android的线程和线程池
  2. Android中的线程模型,
  3. [转载]Android中的线程模型
  4. android异步线程利用Handler将消息发送至UI线程
  5. Android消息机制原理,仿写Handler Looper源码跨线程通信原理--之
  6. Android日志消息的生成详细步骤

随机推荐

  1. android使用volley等网络资源请求时注意
  2. android之微信分享音频
  3. Android创建ListView使用两种适配器的简
  4. android 技术总结
  5. Android 判断是否为模拟器
  6. android中访问 webView加载URL时的respon
  7. Android Studio 关于多个module引用同一j
  8. Lambda for Android
  9. Android学习笔记02
  10. android openGl录制音视频