当前位置:首页 » 《关注互联网》 » 正文

Handler源码解析(高工视角)_m0_37840695的博客

5 人参与  2021年08月26日 09:23  分类 : 《关注互联网》  评论

点击全文阅读


转载请注明出处:https://blog.csdn.net/m0_37840695/article/details/119801922

源码版本:Sources for android 30。(31的版本太新,android studio还没法下载)

还是由易到难,先讲HandlerThread,再讲Handler用于切换到主线程。

一.HandlerThread

1.HandlerThread用法

public class TestActivity extends AppCompatActivity {
    private static final int MSG_GET_DATA_VIA_NETWORK = 101;
    private HandlerThread handlerThread;
    private Handler renderHandler;
    private SurfaceView surfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        surfaceView = findViewById(R.id.surface_view);

        handlerThread = new HandlerThread("surfaceView render thread");
        handlerThread.start();
        renderHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message msg) {

                System.out.println(Thread.currentThread().getName());/********打印:"surfaceView render thread"********/

                if (msg.what == MSG_GET_DATA_VIA_NETWORK) {
                    //render surfaceView on work thread
                    surfaceView.draw(null);
                }
                return true;
            }
        });
    }

    public void refresh(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO: 2021/8/19  get data via network

                renderHandler.sendMessage(renderHandler.obtainMessage(MSG_GET_DATA_VIA_NETWORK, "data json"));
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (handlerThread != null) {
            handlerThread.quit();
        }
    }
}

代码解释:surfaceview支持在工作线程绘制渲染,这里我们用HandlerThread线程绘制、渲染surfaceView。surfaceview要渲染的数据来自网络,我们的项目中的网络请求模块往往会有自己的线程执行网络请求;网络请求得到的数据需要带回到surfaceview的渲染线程中。

2.源码解析

源码中汉字注释是我补充的

2.1 handlerThread = new HandlerThread("surfaceView render thread");

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String threadName) {
        super(threadName);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

2.2 handlerThread.start()触发HandlerThread的run方法;

    @Override
    public void run() {
        mTid = Process.myTid();//********获取线程id
        Looper.prepare();//**********创建looper并保存到当前线程的threadLocal中
        synchronized (this) {
            mLooper = Looper.myLooper();//******从当前线程的threadLocal获取looper
            notifyAll();
        }
        Process.setThreadPriority(mPriority);//********设置当前线程的优先级
        onLooperPrepared();//********空方法,用于子类去实现的
        Looper.loop();//**************让死循环跑起来:循环从mLooper的messageQueue中获取消息,并dispatch给sendMessage的handler->handlerMessage
        mTid = -1;
    }

2.3 Looper.prepare();

    /*Looper.java类中*/
    /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    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");
        }
        sThreadLocal.set(new Looper(quitAllowed));
        //******将looper保存在了当前线程(就是我们的surfaceView的绘制渲染线程)的threadLocal中
    }

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//**********Looper实例化时会创建自己的消息队列
        mThread = Thread.currentThread();
    }

2.4 Looper.loop();

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        //***********************从surfaceview的渲染线程的threadLocal中获取刚刚创建的looper
        final Looper me = sThreadLocal.get();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;
        //looper的消息队列
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        for (;;) {
            Message msg = queue.next(); // might block//********************当队列为空时,这里会阻塞住,当handler发送一个消息添加到队尾时,此处便唤醒了,是通过linux的epoll实现的
            if (msg == null) {
                // No message indicates that the message queue is quitting.
//**********************只有Looper退出、销毁的时候,queue才会在没有消息的情况下被唤醒
                return;
            }
            /*****************下方处理消息的逻辑我们放后面研究***************/
            ...

到目前为止,我们的Looper、MessageQueue已经创建好了,Looper在surfaceview的渲染线程中创建并调用的loop()方法,所以所有的message的处理(handleMessage())都会发生在surfaceview的渲染线程。

2.5 Handler renderHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
    @Override
    public boolean handleMessage(@NonNull Message msg) {
        System.out.println(Thread.currentThread().getName());

        if (msg.what == MSG_GET_DATA_VIA_NETWORK) {
            //render surfaceView on work thread
            surfaceView.draw(null);
        }
        return true;
    }
});

传入looper和Handler.CallBack实例用于构造Handler:

    /**Handler.java中**/
    @UnsupportedAppUsage
    final Looper mLooper;
    final MessageQueue mQueue;
    @UnsupportedAppUsage
    final Callback mCallback;
    final boolean mAsynchronous;
    @UnsupportedAppUsage
    IMessenger mMessenger;
    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by conditions such as display vsync.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;//默认false
    }

当你看到Handler的成员变量,是否觉得它是线程不安全的?不急,我们等下会分析(事实上它通过在相关方法上加锁的方式实现了线程安全)。

2.6 renderHandler.sendMessage(renderHandler.obtainMessage(MSG_GET_DATA_VIA_NETWORK, "data json"));//这行代码是跑在执行网络请求的线程中的

    /**Handler.java**/
    /**
     * 
     * Same as {@link #obtainMessage()}, except that it also sets the what and obj members 
     * of the returned Message.
     * 
     * @param what Value to assign to the returned Message.what field.
     * @param obj Value to assign to the returned Message.obj field.
     * @return A Message from the global message pool.
     */
    @NonNull
    public final Message obtainMessage(int what, @Nullable Object obj) {
        return Message.obtain(this, what, obj);
    }


    /**Message.java**/
    /**
     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
     * members.
     * @param h  The <em>target</em> value to set.
     * @param what  The <em>what</em> value to set.
     * @param obj  The <em>object</em> method to set.
     * @return  A Message object from the global pool.
     */
    public static Message obtain(Handler h, int what, Object obj) {
        /***********Message是单向链表的一个节点,其中的target变量就是发送消息的handler实例,what和obj大家很熟悉,还有一个变量next--指向单向链表中的下一个Message节点************/
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.obj = obj;

        return m;
    }
    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     * 
     */
/*************它将使用过的Message池化了(该Message池是也是一个队列),因为sendMessage可能是高频操作,过程中产生的临时变量不池化会引起内存抖动;我们都应该通过obtain方法获取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();
    }
    /**Handler.java**/
    /**************这里是跑在执行网络请求的线程中的**************/
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    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);/********所以发送消息其实就是将消息添加到消息队列********/
    }




    /**MessageQueue.java**/
    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.");
            }

            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 (;;) {/**************通过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) {/**************这里为true表示原先消息队列为空,执行在surfaceview渲染线程的Looper.loop死循环阻塞在了queue.next()方法中,现在网络请求线程中添加了一个message,通过下方的本地方法(使用的是linux的epoll机制)跨线程定点唤醒queue.next()方法 **************/
                nativeWake(mPtr);
            }
        }
        return true;
    }
    /**Looper.java**/
    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     * 
     */
/******************这里依然是跑在surfaceview的绘制渲染线程中*****************?
    public static void loop() {
/*****************从surfaceview的渲染线程的threadLocal中获取刚刚创建的looper**************/
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;
        /*****************looper的消息队列**************/
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        for (;;) {
            Message msg = queue.next(); /***********此时这里被唤醒,获取到了新添加的Message***********/
            if (msg == null) {
                // No message indicates that the message queue is quitting.
/*********只有Looper退出、销毁的时候,queue才会在没有消息的情况下被唤醒*********/
                return;
            }
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }
/**********将消息的变量恢复初始值,并添加到消息池等待复用**********/
            msg.recycleUnchecked();
        }
    }

2.7 msg.target.dispatchMessage(msg);

我们前面分析了msg.target就是发送msg的handler,我们看handler是如何分发消息的:

    /**Handler.java**/
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {

/************这里依然是跑在surfaceview的绘制渲染线程中**************/

        if (msg.callback != null) {/******** msg的callback优先级最高********/
            handleCallback(msg);
        } else {
            if (mCallback != null) {/********handler的callback优先级其次********/
                if (mCallback.handleMessage(msg)) {
/********这个mCallBack就是我们传入给Handler的(在构建Handler的时候)********/
                    return;
                }
            }
            handleMessage(msg);/********Handler的子类重写的handlerMessage方法优先级最低********/
        }
    }



public class TestActivity extends AppCompatActivity {
    private static final int MSG_GET_DATA_VIA_NETWORK = 101;
    private HandlerThread handlerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SurfaceView surfaceView = findViewById(R.id.surface_view);

        handlerThread = new HandlerThread("surfaceView render thread");
        handlerThread.start();
        Handler renderHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {

/**************跑在surfaceview的绘制渲染线程(HandlerThread)中**************/
            @Override
            public boolean handleMessage(@NonNull Message msg) {

                System.out.println(Thread.currentThread().getName());/**打印"surfaceView render thread"**/

                if (msg.what == MSG_GET_DATA_VIA_NETWORK) {
                    //render surfaceView on work thread
                    surfaceView.draw(null);
                }
                return true;
            }
        });

3.问题列表

3.1我们构造Handler时传入的匿名内部类实例--Handler.Callback是否可能造成内存泄露?

答案:是的。

虽然我们在activity.onDestroy时调用了handlerThread.quit()方法

/**HandlerThread.java**/
    /**
     * Quits the handler thread's looper.
     * <p>
     * Causes the handler thread's looper to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     *
     * @see #quitSafely
     */
    public boolean quit() {/********丢弃消息队列中的消息,退出loop死循环********/
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    /**
     * Quits the handler thread's looper safely.
     * <p>
     * Causes the handler thread's looper to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * Pending delayed messages with due times in the future will not be delivered.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p>
     * If the thread has not been started or has finished (that is if
     * {@link #getLooper} returns null), then false is returned.
     * Otherwise the looper is asked to quit and true is returned.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {/********处理完消息队列中的消息,再退出loop死循环********/
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }


/**Looper.java**/
    public void quit() {
        mQueue.quit(false);
    }
    public void quitSafely() {
        mQueue.quit(true);
    }



/**MessageQueue.java**/
    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();/********移除延时执行的消息********/
            } else {
                removeAllMessagesLocked();/********清空队列********/
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);/********以上代码都是跑在主线程中的,这里我们假设跑在surfaceView的绘制渲染线程中的Looper.loop循环中正在处理一个message,没有因为queue.nex()获取不到消息而阻塞,即handleMessage方法还在跑,意味着不需要通过nativeWake来唤醒********/
        }
    }

我们调用handlerThread.quit()方法只是清空消息队列,如果有一条message的处理很耗时,极端情况是死循环或阻塞了,则匿名内部类Handler.CallBack实例将始终引用我们的activity导致内存泄露。如果非极端情况,比如handleMessage方法只会耗时10s,意味着当前界面关闭10s后才能回收,假设我们当前界面在这10s内进出10次,内存中将存在10个activity实例。所以我们得改进:

public class TestActivity extends AppCompatActivity {
    private static final int MSG_GET_DATA_VIA_NETWORK = 101;
    private HandlerThread handlerThread;
    private Handler renderHandler;
    private SurfaceView surfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        surfaceView = findViewById(R.id.surface_view);

        handlerThread = new HandlerThread("surfaceView render thread");
        handlerThread.start();
        renderHandler = new Handler(handlerThread.getLooper(), new TestHandlerCallback(new WeakReference<>(surfaceView)));
    }

    private static class TestHandlerCallback implements Handler.Callback {
        private WeakReference<SurfaceView> surfaceViewWeakReference;

        public TestHandlerCallback(WeakReference<SurfaceView> surfaceViewWeakReference) {
            this.surfaceViewWeakReference = surfaceViewWeakReference;
        }

        @Override
        public boolean handleMessage(@NonNull Message msg) {
            SurfaceView surfaceView = surfaceViewWeakReference.get();
            if (surfaceView != null) {

                System.out.println(Thread.currentThread().getName());/********打印:"surfaceView render thread"********/

                if (msg.what == MSG_GET_DATA_VIA_NETWORK) {
                    //render surfaceView on work thread
                    surfaceView.draw(null);
                }
            }
            return true;
        }
    }

3.2 Handler是如何保证线程安全的?

显然我们会在多线程中使用同一个handler对象,即在多线程中调用这行代码:

renderHandler.sendMessage(renderHandler.obtainMessage(MSG_GET_DATA_VIA_NETWORK, "data json"));

先看renderHandler.obtainMessage方法:

/**Handler.java**/
    @NonNull
    public final Message obtainMessage(int what, @Nullable Object obj) {
        return Message.obtain(this, what, obj);
    }



/**Message.java**/
    public static Message obtain(Handler h, int what, Object obj) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.obj = obj;

        return m;
    }
    public static Message obtain() {
        synchronized (sPoolSync) {/********加了sPoolSync对象锁,保证从message池获取message的线程安全********/
            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();
    }

再看renderHandler.sendMessage方法:

/**Handler.java**/
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    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);
    }


/**MessageQueue.java**/

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {/********以this(当前消息队列)为锁,保证this在不同线程enqueueMessage的线程安全********/
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }

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

另外,我们在surfaceView的绘制渲染线程从messageQueue取出message,同时在别的线程往messageQueue添加message,是如何保证线程安全的?

/**MessageQueue.java**/
/********在surfaceView的绘制渲染线程从messageQueue取出message********/
    @UnsupportedAppUsage
    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        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) {/**********这里也是加this(messageQueue对象锁),对messageQueue存取加同一把锁,则多线程存与取方法中2个synchronized代码块将是串行的**********/
                // Try to retrieve the next message.  Return if found.
                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) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        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 {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                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);
            }

            // 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.wtf(TAG, "IdleHandler threw exception", t);
                }

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

另外,Looper中的messageQueue并没有volatile修饰,一个线程往其中添加了一个message,有一个线程怎么读到最新的messageQueue呢?

答案:还是存与取2个方法加了锁实现的。根据JMM(java内存模型):

现在我们知道存与取中相应的2个synchronized代码块是串行的,一个添加message的线程获到this锁时(对应图中Lock位置),它会从主内存中Read最新的messageQueue,添加完message释放锁(对应Unlock位置)前,它会将添加了message的messageQueue写(对应Write位置)到主内存中。此时另外一个线程获取到this锁了,来到了图中Lock位置,它会读取最新的messageQueue。

看到这儿,其实咱已经掌握了Handler的原理。Handler就是用于将“代码执行和数据”切换到其Looper所在的线程的。而使用handler切换到主线程,只不过是该handler的looper是在主线程创建而已。

二.Handler用于切换到主线程

1.用法

public class TestMainHandlerActivity extends AppCompatActivity {
    private static final int MSG_HELLO_HANDLER = 101;
    private Handler handler = new MainHandler(new WeakReference<>(TestMainHandlerActivity.this));
    private TextView textView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.text_view);
    }

    public void refresh(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                // TODO: 2021/8/20  get data via network

                handler.sendMessage(handler.obtainMessage(MSG_HELLO_HANDLER, "data json"));
            }
        }).start();
    }

    private static class MainHandler extends Handler {
        private WeakReference<TestMainHandlerActivity> weakReference;

        public MainHandler(WeakReference<TestMainHandlerActivity> weakReference) {
            super(Looper.getMainLooper());/********这儿是与第一节唯一不同之处,app进程启动后创建了主线程的同时,也创建好了主线程自己的looper,而我们构造的handler,就是使用的主线程的looper********/
            this.weakReference = weakReference;
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            TestMainHandlerActivity activity = weakReference.get();
            if (activity != null) {
                if (msg.what == MSG_HELLO_HANDLER) {
                    activity.textView.setText((String) msg.obj);
                }
            }
        }
    }
}

2.源码解析

/**ActivityThread.java**/

    public static void main(String[] args) {/********我们app程序的入口,跑在主线程中**********/
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // Install selective syscall interception
        AndroidOs.install();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        // Call per-process mainline module initialization.
        initializeMainlineModules();

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();/********主线程创建了自己的looper**********/

        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

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

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

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();/********主线程开始了自己的looper.loop死循环;接下来就是如果有界面绘制、渲染message或用户与界面交互相关message添加到looper的messageQueue,此loop死循环就跑起来,如果messageQueue为空,就会阻塞在queue.next(),等待有message添加时被唤醒。而我们创建的handler,也是使用的主线程的looper,意味着我们在工作线程中handler.sendMessage(handler.obtainMessage(MSG_HELLO_HANDLER, "data json")),此message也是进入主线程looper的messageQueue中**********/

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




/**Looper.java**/

    @Deprecated
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = sThreadLocal.get();
        }
    }
    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));
    }

点击全文阅读


本文链接:http://m.zhangshiyu.com/post/26171.html

线程  消息  渲染  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1