handler源码分析--以及手写一个handler

  • handler的基本使用:
    @OnClick(R.id.test_handler_activity)
    public void testHandler(View view) {
        handler.sendEmptyMessageDelayed(TEST1,1000);
    }


    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            switch (what) {
                case TEST1:
                    startActivityBtn.setText("handle test");
                    break;
            }
        }
    };
  • handler源码分析:
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

实际就是封装了一个message对象,调用sendMessageDelayed方法。

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

最终都会调用到这个sendMessageAtTime方法。

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

注意,这个uptimeMillis指的就是什么时间点进行执行。是SystemClock.uptimeMillis() + delayMillis。我们这里默认把它当成delayMillis也行,因为仅仅只是加上一个固定值而已。

拿到mQueue消息队列,就调用enqueueMessage方法:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;  // 这里msg.target进行了赋值,后面有用到
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

msg就是我们sendMessage发过来的消息。最后会调用MessageQueue的enqueueMessage方法:
MessageQueue.java

// when就是上面的uptimeMillis,就是sendMessageDelayed调用时传的delay值
    boolean enqueueMessage(Message msg, long when) {
        // msg.target = this;就是当前handler对象
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        // 当前message是否正在使用中
        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();  // 标记该message正在使用中
            msg.when = when;  // when是delay
            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 {
                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;
                    }
                }
                // 把message2放进链表的后面
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
           ......
        }
        return true;
    }

上面enqueueMessage方法,主要就是做了一件事,就是把msg消息,放进队列里面。怎么放进队列里面,就会进行一系列的判断:
(1)首先判断队列的消息是否为null,第一次放message时。mMessages肯定为null。msg就是我们要发送的message。

            msg.when = when;  // 当前消息的when是delay
            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;  
            }

所以走进这个if。让msg.next = p。 mMessages = msg。这样mMessages链表里面就存放了第一个message。
(2)判断当前when<p.when。 when是指当前发送的消息延迟时间。p.when是指链表的第一个消息的延迟时间。如果当前要发送的消息延迟时间更小。那就让msg.next = p。 mMessages = msg。让当前发送的消息排在链表的最前面。
(其实就是消息按when时间从小到大插入链表。)

(3)后面的else也是遵循这个规律,把消息放入链表中,按照when的大小,从小到大进行排列插入:

		else {
                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;
                    }
                }
                // 把message2放进链表的后面
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

当p == null。或者当前消息小于当前链表当前节点。那就退出for循环。然后把当前要发送的消息插入进链表就可以了。

                    if (p == null || when < p.when) {
                        break;
                    }

prev记录的是要插入的节点的前一个节点。prev.next就是下一个要指向的就是msg。msg.next = p那就成功把msg插入链表中。

                msg.next = p; // invariant: p == prev.next
                prev.next = msg;

扯这么多,就是为了做一件事,就是把当前要发送的message插入到链表适当的位置,何为适当位置,按照when从小到大插入进来。

为什么要用到链表结构。因为这中间做的插入操作较为频繁,相对于数组结构效率会提高很多。

  • 那怎么执行到handlerMessage的呢?
    其实我们在new Handler时,前面和后面,都执行了Looper.prepare和Looper.loop()方法。
    从两处可以看到:
    1、看Handler的构造方法:
    public Handler(Callback callback, boolean async) {
       .....

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

这里看到

mLooper = Looper.myLooper();

如果mLooper循环器为空,那就会抛出异常。我们运行代码没有抛出异常,说明,在调用构造方法前,就已经初始化了mLooper对象了。看看Looper.myLooper方法:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

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

是通过ThreadLocal的get方法,拿到的looper对象。在这之前肯定是有地方set过的。

2、在ActivityThread的main方法。

        Looper.prepareMainLooper();  // 入口函数main,已经帮我们写了Looper.prepare()

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

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();   // 循环。

可以看到Looper.prepareMainLooper方法。我们去Looper.java看:

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            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));
    }

果然,在prepare方法这里,有进行了ThreadLocal的set方法。把Looper对象,设置进去。这个ThreadLocal本质上就是一个map存放键值对。而这个map,一个线程仅有一份map。而这个map的key是存放ThreadLocal对象,value存放的是looper对象。

为什么要这样做:
其实就是创建一个Looper,并且保证一个Thread线程中,只有一个Looper对象!

看ThreadLocal源码就知道:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    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 void set(T value) {
        Thread t = Thread.currentThread(); // 通过线程拿到map
        ThreadLocalMap map = getMap(t); //拿到map集合
        if (map != null)
            map.set(this, value); // 设置looper对象
        else
            createMap(t, value);
    }
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

sThreadLocal就是Looper的一个常量。所以key值都是相同的,都是sThreadLocal常量对象。不一样的是,存放的map不一样。一个线程对应一个map。可以通过当前线程t,拿到当前线程的ThreadLocalMap对象。

Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);

拿到当前线程对象,就可以拿到对应的ThreadLocalMap对象。ThreadLocalMap就是Thread对象的一个成员变量。
Thread.java

    // 一个线程对应一个
    ThreadLocal.ThreadLocalMap threadLocals = null;

拿到当前线程对应的map之后,就可以map.set(this, value);。
以当前sThreadLocal对象作为key,以looper对象作为value。

在这里插入图片描述
总结:Looper.prepare方法就是做了一件事,创建Looper对象,设置进当前线程的map集合里面。

当我们创建handler实例时:

    public Handler(Callback callback, boolean async) {
        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 static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

就会去调用sThreadLocal.get方法

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

通过当前线程对象,找到对应的map集合,sThreadLocal对象(key),拿到对应的entry组合,再通过entry获取到对应的value:

       mQueue = mLooper.mQueue;

原来mQueue是在这里被赋值的,刚刚在sendMessage那里就看到你了!在sendMessageAtTime的时候就看到了。

  • 最终究竟是怎么调用handlerMessage方法的:
    讲了这么多,还是没到handlerMessage方法。那就是Looper的loop方法。
    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;
            }
       .....
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } 
         .....
            msg.recycleUnchecked();
        }
    }

myLooper拿到当前线程的looper对象,就可以拿到对应的队列,进入for无限循环语句,把队列里面的消息一个个next出来。然后调用:

msg.target.dispatchMessage(msg);

这个msg.target不就是刚刚handler对象嘛,去
Handler.java:

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

这不就调用了handlerMessage了。结果不重要,重要的是思路。

  • 重点
    1、handler在sendMessage时,做了什么:
    就是把消息放进链表中,按照发送的时间顺序从小到大插入进链表。频繁插入操作,使用链表比较合适。

2、handler是否保证一个线程,只有一个Looper对象。怎么保证的?
肯定要保证一个线程只有一个Looper对象。不然就会出现线程间消息接收错乱。出现脏读现象,就是已经接收处理完成的消息,在其他线程又处理一遍。
怎么保证一个线程只有一个Looper对象,用ThreadLocal。一个线程对应一份map集合。以ThreadLocal对象作为key,以Looper对象作为value。存放进这个map集合里面。后面要获取,可以根据当前线程对象,拿到对应的map集合,就可以拿到对应的looper对象。

  • 我自己手写一个简易版的Handler框架。
    1、把握核心要点:
    (1)使用链表存储Message对象
    (2)使用ThreadLocal存储Looper对象
public class MyHandler {
    MyMessageQueue mQueue;

    public MyHandler() {
   //     MyLooper.prepare();
        MyLooper looper = MyLooper.myLooper();

        if(looper == null){
            throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
        }

        mQueue= looper.mQueue;
    }
    
    public void handleMessage(MyMessage msg) {
    }
    public void sendMessage(MyMessage MyMessage) {
        sendMessageDelayed(MyMessage,0);
    }

    public final boolean sendMessageDelayed(MyMessage msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, System.currentTimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(MyMessage msg, long uptimeMillis) {
        MyMessageQueue queue = mQueue;
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(MyMessageQueue queue, MyMessage msg, long uptimeMillis) {
        msg.target = this;
        return queue.enqueueMessage(msg, uptimeMillis);
    }
}
public class MyLooper {
    static final ThreadLocal<MyLooper> sThreadLocal = new ThreadLocal<>();

    public static void prepare() {
        sThreadLocal.set(new MyLooper());
    }

    MyMessageQueue mQueue;

    public MyLooper() {
        mQueue = new MyMessageQueue();
    }

    public static void loop() {
        MyLooper looper = myLooper();
        for(;;){
            MyMessageQueue queue = looper.mQueue;

            MyMessage message = queue.next();

            if(message == null){
                return;
            }

            message.target.handleMessage(message);
        }
    }

    static MyLooper myLooper() {
        return sThreadLocal.get();
    }
}
public class MyMessage {
    public Object obj;
    public MyHandler target;
    public long when;
    public MyMessage next;
}
public class MyMessageQueue {
    private MyMessage mMessages;

    public MyMessage next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        for (;;) {

            synchronized (this) {
                // Try to retrieve the next message. Return if found.
                final long now = System.currentTimeMillis();
                MyMessage prevMsg = null;
                MyMessage 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);
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready. Set a timeout to wake up
                        // when it is ready.
                    } else {
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        return msg;   // 拿到了当前要处理的消息
                    }
                } else {
                    return  null;
                }

                if (pendingIdleHandlerCount <= 0) {
                    continue;
                }
            }
        }
    }

    public boolean enqueueMessage(MyMessage msg, long when) {
        synchronized (this) {
            msg.when = when;
            MyMessage p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
            } else {
                MyMessage prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
        }
        return true;
    }
}

记得要在Handler构造方法之前,调用Looper.prepare方法,创建好Looper对象。然后在sendMessage之后调用Looper.loop方法,轮询器开始进行轮询消息。

  • 享学总结:
    1、MessageQueue是负责管理message消息的容器,线程间内存是共享的,所以主线程和子线程可以共享MessageQueue这个消息队列。所以主线程在main函数调用Looper.loop保证死循环不退出,就是不断地循环从MessageQueue取出消息,将取出的消息传递到handler.dispatch去处理取出来的消息。(跨线程通信的背后逻辑:内存共享,这里的内存共享指的是主线程和子线程之间内存共享)
    2、Handler的内存泄露:
    (1)涉及了JVM的垃圾回收,判断对象是否需要回收的两种方法
    (2)handler匿名内部类,持有外部类的Activity.this对象。而Message又持有Handler对象。MessageQueue又持有Message对象。Looper持有MessageQueue。ThreadLocal持有Looper对象。(等下放源码就可以很清晰)
    持有链:static sThreadLocal --> Looper --> MessageQueue --> Message --> handler --> Activity.this。
    sThreadLocal就是静态对象,即GCRoot生命周期和跟随整个应用程序。所以在这条GCRoot链相关的对象,都不会被垃圾回收。当Activity执行onDestory时,里面的message还没有被拿出来处理,那MessageQueue还是会持有着Message对象,这样activity对象是不会被回收掉的,那就会内存泄露了。只有当Message消息处理完了,Message对象才不会被MessageQueue持有。
    (3)解决Handler内存泄露的方法:
    ①让Handler设为static静态匿名内部类,静态对象不具备持有外部类对象,如果真的需要外部类Activity对象,可以通过Handler构造方法,传入Activity对象,并且使用弱引用持有Activity对象。
    MyHandler myHandler = new MyHandler(this);
    private static class MyHandler extends Handler {
        private final WeakReference<Activity> weakReference;

        public MyHandler(Activity activity) {
            weakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    }

②在Activity执行distroy时,把当前activity的message消息从MessageQueue从remove掉。
只要打断其中一个持有链,就可以回收Activity对象了。

匿名内部类,持有外部对象的引用:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public void testHandler(View view) {
        handler.sendEmptyMessageDelayed(TEST1,1000);
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            switch (what) {
                case TEST1:
                    Log.i(TAG, "handleMessage: ");
                    break;
            }
        }
    };
}

MessageQueue.java的enqueueMessage方法:
使得MessgaeQueue持有msg对象的引用。

mMessgaes = msg;
....
prev.next = msg;

3、为何主线程可以new Handler? 如果想要在子线程new Handler该做什么准备?
(1)ActivityThread的main方法就是在主线程上运行的。main方法上,做了Looper.prepare,初始化Looper对象。以及在创建了handler对象之后,做了Looper.loop方法,可以轮询队列消息。Handler在初始化时,会去拿Looper对象:

    public Handler(Callback callback, boolean async) {
       .....
        mLooper = Looper.myLooper();  // 关键!!!!
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        ....
    }

如果想要在子线程创建handler对象,在创建handler对象之前没有做Looper.prepare动作,就会抛异常。 在创建handler对象之后没有Looper.loop就不会从消息队列取出消息进行对应处理,整个handler就不会运转起来。

4、子线程创建handler涉及并发同步问题。因为想拿到子线程创建Handler对应的Looper对象,会有可能出现并发问题:

public class HandlerActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        handlerThread.start();
    }

    MyHandlerThread handlerThread = new MyHandlerThread();
    Handler handler1 = new Handler(handlerThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };
}
public class MyHandlerThread extends Thread{
    private Looper looper;
    @Override
    public void run() {
        super.run();
        Looper.prepare();
        Handler handler = new Handler();
        Looper.loop();
    }

    public Looper getLooper() {
        return Looper.myLooper();
    }
}

两个线程,主线程先执行了getLooper方法,子线程再执行MyHandlerThread里面的run方法。那很有可能主线程getLooper拿到的looper对象是为null,因为子线程还没执行run方法,looper.prepare还没执行,即还没初始化。

解决方法:SDK已经提供了一个类叫HandlerThread。让getLooper方法获取looper对象和 run方法中初始化looper对象,进行互斥访问。

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();  // 互斥访问
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
        // 内置锁 锁的互斥访问机制
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

(1)wait立刻阻塞状态,会释放锁对象。sleep挂起,不释放锁,等待指定时间。
(2)notifyAll唤醒所有wait代码,因为有可能有多处地方调用getLooper方法,那就有多个wait方法需要唤醒,而notify只是唤醒一个wait代码
(3)为什么使用while循环,而不是if语句:因为有可能在别处没有初始化mLooper变量的地方使用了synchronized代码,并且用的锁是同一个对象,并且在里面调用了notifyAll,从而把getLooper方法给唤醒,如果使用if语句,那被唤醒之后,mLooper变量还是为null。使用while可以防止别处地方唤醒导致mLooper变量为null。

5、如果不同的handler处于不同线程中,如何保证存消息和取消息线程安全?(注意:子线程可以创建Handler,一个线程可以创建多个Handler对象,但一个线程只能对应一个Looper对象,这是ThreadLocal机制,一个Looper对应一个MessageQueue。但是可以多个线程拿到同一个Looper对象来进行存取消息,因为ThreadLocal线程隔离一般不这么做):
(1)在enqueueMessage加上synchroized锁,只能同时有一个线程,往消息队列添加消息。
(2)next取消息,也是要加synchroized锁,目的是存消息和取消息是互斥访问的,保证存和取消息同时进行时是线程安全的。
MessageQueue.java

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        // 多个线程,往一个MessageQueue里面添加消息。  同步锁,线程安全
        synchronized (this) {
	// 存消息
        }
        return true;
    }

    Message next() {
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);
            // 存消息和取消息,不是在同一个线程,保证存消息和取消息互斥访问,在同一瞬间只有一个线程在存或者取
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
	       //取消息
                        return msg;
                    }
                } 
    }

6、Handler的消息Message对象,是怎么管理的?是直接new创建Message对象,然后处理完消息之后,就直接交给JVM垃圾回收对象吗?:
创建消息是用obtain方法,obtain方法就是负责从sPool池子中取Message对象,如果池子是没有Message对象的,才手动new一个Message对象。

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

消息对象在Looper.loop使用完了,要进行回收,回收并不是交给JVM垃圾回收对象。而是把消息内容清空,并存入sPool池中。

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

享元模式。对象复用,防止频繁创建对象回收对象导致内存抖动和内存碎片的问题。

7、Looper死循环会不会导致卡死?:消息队列里面没有消息,就让它休息睡眠,把CPU资源让出去,和ANR没关系。(ANR是什么?)
8、什么是epoll。非阻塞忙轮询和阻塞轮询是什么?:
(1)非阻塞轮询,就是不管IO流里面有没有数据,都会一直遍历所有的流,一直忙着在for循环中。如果流没有数据的话,就一直在for循环,一直不会进入if语句处理IO。这样只会浪费CPU资源

while(true) {
	for(i -> stream[]){
		if(has data) {
			// read data until unavalilable
		}
	}
}

(2)阻塞轮询,使用select函数:
在for循环之前,加一个select语句,可以检测到所有的流中有IO事件发生,就会进入for循环来遍历所有的流。select方法只要有IO事件发生就遍历所有的流,并不知道具体是哪一个流有IO事件。这样只能无差别轮询所有的流,比非阻塞轮询稍微好一点,但一样浪费CPU

while(true) {
	select(stream[])
	for(i -> stream[]){
		if(has data) {
			// read data until unavalilable
		}
	}
}

(3)而epoll,它比select更好一点,当有IO事件发生时,它可以知道具体哪些流发生了怎样的IO事件。这样进入for循环轮询,只轮询有发生IO事件的流就好了

while(true) {
	active_stream[] = epoll_wait();
	for(i -> active_stream[]){
			// read data until unavalilable
	}
}

handler中创建MessageQueue对象,就会调用nativeInit方法,初始化epoll。
在MessageQueue的next方法:
nativePollOnce就是刚刚的epoll_wait判断是否需要阻塞。

for(;;){
    //....
	nativePollOnce(ptr,nextPollTimeoutMillis);
}

在enqueueMessage方法中:
有消息添加进队列,通过nativeWake来唤醒looper循环机制。

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
    }

9、同步屏障:
UI刷新消息的优先级是最高的。屏障消息就是target为null的消息。
Message分为三类,同步消息、异步消息、屏障消息。
在ViewRootImpl有一个scheduleTraversals发送一个异步消息(先发送了一个屏障消息,优先级最高。),再setAsynchronous设置为异步消息。
在这里插入图片描述
next取消息,怎么取的。仍旧从队列头开始取,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值