Android Handler机制 同步屏障

Android Handler机制

1.什么是handler?

我们都知道在App开发中,View的刷新等操作都需要在App的主线程来执行,那么我们需要在子线程更新UI的操作是可以使用Handler来完成UI的更新。

Handler的可以post一个延时消息的机制,我们可以使用Handler来完成几个简单的定时任务。

在一些子线程之间的通信,我们也可以使用Handler来实现。

那么什么是Handler?

Handler是Android 用来处理消息通信机制,Handler可以将一个任务切换到构成handler的looper所在的线程中去出处理。

所以Handler能够保证某一个模块在被多线程访问的时候,让多线程发出的消息有序安全的在同一个线程执行的消息。比如工作线程对Android的UI更新操作都需要使用Handler来保证UI的更新动作只能在UI线程中处理;

2.Handler的作用

多个线程并发更新UI的同时 保证线程安全

能够保证某一个模块在被多线程访问的时候,让多线程发出的消息有序、安全的在Handelr所在的线程执行的消息。

在一个App启动的时候,system_server进程会向zygote进程发送创建进程的请求,之后Zygote进程fork出新的子进程,即App进程,之后进入ActivityThread的main方法开始App的初始化工作;

在main方法中:

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

thread.getHandler()方法:

@UnsupportedAppUsage
final Handler getHandler() {
    return mH;
}

final H mH = new H();
class H extends Handler {

所以在app启动的时候回去创建一个Handler,Handler是支撑整个Android系统运行的基础,本质上Android系统都是由事件驱动的,而Handler能够保证所有其他工作线程的访问能够安全、有序的分发到主线程中。

3.Handler的简单使用和避免内存泄漏

handler的使用大概分为三类:

1.工作线程与UI主线程的消息通信;

2.工作线程、子线程需要让主线程执行一个延时任务;

3.工作线程中使用Handler实现并发安全(Android中不常用,只是一种方式)

具体使用流程这里不做介绍

Handler使用需要注意内存泄漏

我们handler的创建一般会在Acivity中,使用如下的方式:

//错误示例
    private var uiHander1 = object : Handler(Looper.getMainLooper()){
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
        }
    }

    inner class uiHander3: Handler(){
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
        }

内部类和匿名内部类都会持有外部类的引用,但是我们创建的mHander实例可能需要在耗时线程中使用,所以会造成内存泄漏。

示例:

public class TestActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable  Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    
    class UIHandler extends Handler{}
}

可以用通过Lint来看看上面代码:

image-20210522142756914

Handler在Activity中创建使用内部类和匿名内部类都是不正确的,正确的使用应该如下:

使用静态内部类或者将类单独新建,并且将使用到的Context或者Acivity使用弱引用:

fun work(){
        thread {
            Log.e("yhp", "workThread do some work!")
            Thread.sleep(2000)
            uiHandle2?.sendEmptyMessage(0)
        }
    }

    var uiHandle2: Handler? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_empty)

        uiHandle2 = UIHandler(this)
        work()
        
    }


    class UIHandler <T : Activity?> (t: T) : Handler(Looper.getMainLooper()) {
        var weakReference: WeakReference<T?> = WeakReference(t)
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            weakReference.get()?.let {
                //UI线程
                Log.e("yhp", "uiThread do some work!")
            }
        }

    }

工作线程中使用Handler

工作线程中Handler的创建需要单独开启Looper

class ThreadHanderlActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_thread)
        startWorkThread()
        btn_send.setOnClickListener {
            workHandler?.run {
                sendEmptyMessage(0)
            }
        }

        btn_stop.setOnClickListener { stopWork() }

    }

    //子线程中的Handler
    var workHandler: Handler? = null

    //子线程
    var workThread: Thread? = null

    //记录子线程开启的Looper,在任务取消的时候使用quite结束Looper,此时子线程才算结束
    var workHandlerLooper: Looper? = null

    //主线程去开启子线程
    private fun startWorkThread(){
        workThread = thread {
            Looper.prepare()
            workHandlerLooper = Looper.myLooper()?.apply {
                //不能使用这种方式,因为这种方式默认为匿名内部类,一样持有外部类引用
               /* workHandler = object : Handler(this){
                    override fun handleMessage(msg: Message) {
                        super.handleMessage(msg)

                    }

                }*/
                workHandler = WorkHandler(this)
            }
            //处理耗时任务
            Log.e("yhp", "workHandler Thread do work!")
            Thread.sleep(2000)
            Looper.loop()
            //如果不调用Looper.quit(),该线程下面的部分将不会执行
            Log.e("yhp", "workHandler Looper end")
        }
    }


    private fun stopWork(){
        workHandlerLooper?.quit()
    }
    override fun onDestroy() {
        super.onDestroy()
        workHandlerLooper?.quit()
    }

    //不能使用inner class,因为使用inner class相当于是一个内部类 单独使用class相当于一个静态内部类,不持有外部类引用
    class WorkHandler @JvmOverloads constructor(looper: Looper, callback: Callback? = null) : Handler(looper, callback) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            Log.e("yhp", "子线程的Handler收到消息!")
        }
    }
}

在上面的实例中,如果在onDestroy中不将Lopper停止,那么工作线程将会一直执行, Looper.loop()后面的也不会执行;

image-20210522153623850

注意点:

1.子线程创建的Handler也不能使用内部类或者匿名内部类;

2.子线程创建Handler时 Looper.loop()后面将不会执行;

3.在Activity关闭或者其他因素时需要手动调用Looper?.quit()停止工作线程;

4.Handler机制及源码

主要成员

  1. Message:消息本体
  2. Hanlder:消息的发起者
  3. Looper:消息的遍历者
  4. MessageQueue:消息队列

Message

关键信息

when:消息需要被执行的时间

target:发送消息的Handler对象

callback:Runnable形式的消息

next:该消息的下一个消息

image-20210522170745848

Hanlder

负责消息发送和消息分发

MessageQueue

主要用来消息的插入、获取,维护消息的顺序;

Looper

Looper主要循环,不断的去取出MessageQueue中的messsage,然后转发消息给Handler

主要流程

Looper和MessageQueue创建

new Handler之前调用Looper.prepare()

Looper.prepare()主要是初始化Looper,此时newHandler操作的当前线程存在一个不可变的sThreadLocal变量;

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

prepare中会new一个Looper给sThreadLocal,所以sThreadLocal.get()已经存在Looper时,那么就不允许再次创建,所以这里保证了一个线程只允许拥有一个Loper

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实例化中创建了一个MessageQueue,并记录了当前线程

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

那么到此可以知道:

一个线程只允许拥有一个Loper和一个MessageQueue

Handler的初始化

主要是获取到了当前线程Looper的实例和MessageQueue的实例

public Handler(@Nullable Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

Looper.loop()

主要工作是使用MessageQueue的next()获取到消息,然后使用消息的target即发送消息的Handler实例调用dispatchMessage将消息分发至Handler中;

 public static void loop() {
        final Looper me = myLooper();
        me.mInLoop = true;
        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);
                
            } 
            msg.recycleUnchecked();
        }
    }

MessageQueue的enqueueMessage方法

 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循环是否被停止
            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;
            //当队列最顶端的消息不存在时,将当前消息移到最顶端,指向下一个p其实是为空
            //mBlocked记录当前loop循环是否已经休眠,如果执行时间已经到了那么会根据当前的休眠状态来设置是否需要唤醒的标志位
            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();
                //如果当前队列最顶端消息存在,则会根据消息的执行时间将传入的msg插入到相应的位置
                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;
    }

大概流程就是将传入的Message插入到按照执行时间排序的队列中,并根据最顶端的消息的执行时间和线程的休眠状态来设置唤醒标志位,然后唤醒。

MessageQueue的next()方法

    Message next() {
        //如果消息循环已经退出并被释放,则在这里返回。
        //如果应用程序试图在不支持的quit之后重新启动一个循环程序,就会发生这种情况。
        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) {
            // 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;
            }

            //如果Looper已经被终止,则返回空
            // 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;
    }
}

根据队列最顶高端的消息执行时间和条件,处理睡眠的时间或者返回最顶端的消息,消息屏障见后面章节,我们应用层发送的消息都不是同步屏障。

Handler发送消息

image-20210522180434131
image-20210522180447083

Handler发送的消息或者post的Runnable都会进入enqueueMessage中,也就进入了MessageQueue的enqueueMessage方法。

Handler消息分发

Looper.loop()最终调用Message的发送者handler的dispatchMessage方法

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

handleCallback:执行Runnable任务

handleMessage:也就是我们自己重写的handleMessage方法

消息回收

Looper.loop()最终调用Message的发送者handler的dispatchMessage方法之后会使用

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

这步骤也就是将处理过的Message中的所有参数置为初始值,然后放到一个队列中,这个回收队列最大值为50.

private static final int MAX_POOL_SIZE = 50;

所以Handler可以使用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();
}

5.消息同步屏障

MessageQueue的next()方法中会有一个msg.target == null的判断,这个是用来小处理消息同步屏障的

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


什么是同步屏障

线程的消息都是放到同一个MessageQueue里面,取消息的时候是互斥取消息,而

且只能从头部取消息,而添加消息是按照消息的执行的先后顺序进行的排序,那么问题来了,同一个时间范围内的消息,如果它是需要立刻执行的,那我们怎么办,按照常规的办法,我们需要等到队列轮询到我自己的时候才能执行哦,那岂不是黄花菜都凉了。所以,我们需要给紧急需要执行的消息一个绿色通道,这个绿色通道就是同步屏障的概念。

屏障的意思即为阻碍,顾名思义,同步屏障就是阻碍同步消息,只让异步消息通过。如何开启同步屏障呢?

MessageQueue#postSyncBarrier()
private int postSyncBarrier(long when) {
    // Enqueue a new sync barrier token.
    // We don't need to wake the queue because the purpose of a barrier is to stall it.
    synchronized (this) {
        final int token = mNextBarrierToken++;
        final Message msg = Message.obtain();
        msg.markInUse();
        msg.when = when;
        msg.arg1 = token;

        Message prev = null;
        Message p = mMessages;
        if (when != 0) {
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
        }
        if (prev != null) { // invariant: p == prev.next
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}

postSyncBarrier方法并没有设置target ,并且该方法已经新建了一条消息插入到队列最顶端。

同步消息的应用场景

似乎在日常的应用开发中,很少会用到同步屏障。那么,同步屏障在系统源码中有哪些使用场景呢?Android 系统中

的 UI 更新相关的消息即为异步消息,需要优先处理。

比如,在 View 更新时,draw、requestLayout、invalidate 等很多地方都调用了

ViewRootImpl#scheduleTraversals() ,如下:

ViewRootImpl.java

   void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

postCallback() 最终走到了 Choreographer postCallbackDelayedInternal()

Choreographer.java

private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {
    if (DEBUG_FRAMES) {
        Log.d(TAG, "PostCallback: type=" + callbackType
                + ", action=" + action + ", token=" + token
                + ", delayMillis=" + delayMillis);
    }

    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

        if (dueTime <= now) {
            scheduleFrameLocked(now);
        } else {
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

由于 UI 更新相关的消息是优先级最高的,这样系统就会优先处理这些异

步消息。

最后,当要移除同步屏障的时候需要调用 ViewRootImpl#unscheduleTraversals() 。

void unscheduleTraversals() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        mChoreographer.removeCallbacks(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
}

结论:

同步屏障的设置可以方便地处理那些优先级较高的异步消息。当我们调用

Handler.getLooper().getQueue().postSyncBarrier() 并设置消息的 setAsynchronous(true) 时,target 即 为 null ,也就开启了同步屏障。当在消息轮询器 Looper 在 loop() 中循环处理消息时,如若开启了同步屏障,会优先处理其中的异步消息,而阻碍同步消息。

6.Handler机制流程图

主要流程如下图:

Handler

5.HandlerThread

HandlerThread是Thread的子类,严格意义上来说就是一个线程,只是它在自己的线程里面帮我们创建了Looper

@Override
    public void run() {
        // 1. 获得当前线程的id
        mTid = Process.myTid();
        // 2. 创建1个Looper对象 & MessageQueue对象
        Looper.prepare();
        // 3. 通过持有锁机制来获得当前线程的Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();
            // 发出通知:当前线程已经创建mLooper对象成功
            // 此处主要是通知getLooper()中的wait()
            notifyAll();
        }
        // 4. 设置当前线程的优先级
        Process.setThreadPriority(mPriority);
        // 5. 在线程循环前做一些准备工作
        // 该方法实现体是空的,由子类决定是否实现
        onLooperPrepared();
        // 6. 进行消息循环,即不断从MessageQueue中取消息 & 派发消息
        Looper.loop();
        mTid = -1;
    }

工作原理

HandlerThread继承Thread,在Thread开始执行时跟主线程在ActivityThread.main()方法内执行代码逻辑类似,初始化Looper--Looper.prepare(),轮询消息--Looper.loop();

初始化Handler时,使用HandlerThread线程的Looper对象初始化---- new Handler(Looper)构造方法。

使用实例

 // 步骤1:创建HandlerThread实例对象
  // 传入参数 = 线程名字,作用 = 标记该线程
  HandlerThread mHandlerThread = new HandlerThread("handlerThread");
  // 步骤2:启动线程
  mHandlerThread.start();
  // 步骤3:创建工作线程Handler & 复写handleMessage()
  // 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与 其他线程进行通信
  // 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
  Handler workHandler = new Handler( handlerThread.getLooper() ) {
            @Override
            public boolean handleMessage(Message msg) {
                ...//消息处理
                return true;
            }
        });

  // 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
  // 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
  // a. 定义要发送的消息
  Message msg = Message.obtain();
  //消息的标识
  msg.what = 1;
  // b. 通过Handler发送消息到其绑定的消息队列
  workHandler.sendMessage(msg);

// 步骤5:结束线程,即停止线程的消息循环
  mHandlerThread.quit();

getLooper同步问题

public Looper getLooper() {
        // 若线程不是存活的,则直接返回null
        if (!isAlive()) {
            return null;
        } 
        // 若当前线程存活,再判断线程的成员变量mLooper是否为null
        // 直到线程创建完Looper对象后才能获得Looper对象,若Looper对象未创建成功,则阻塞
        synchronized (this) {
  
      
            while (isAlive() && mLooper == null) {
                try {
                    // 此处会调用wait方法去等待
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        // 上述步骤run()使用 持有锁机制 + notifyAll()  获得Looper对象后
        // 则通知当前线程的wait()结束等待 & 跳出循环
        // 最终getLooper()返回的是在run()中创建的mLooper对象
        return mLooper;
    }

使用同步锁、wait() 和 notifyAll()

即 在run()中成功创建Looper对象后,立即调用notifyAll()通知 getLooper()中的wait()结束等待 & 返回run()中成功创建的Looper对象,使得Handler与该Looper对象绑定。

参考文章:https://www.jianshu.com/p/db915d207e6d

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容