android主线程与Handler

2019-10-30  本文已影响0人  丸子不爱吃丸子

回忆一个简单的Handler使用

class TestActivity : AppCompatActivity() {
    private var mUIHandler = Handler{
        when(it.what) {
            1 -> {
                Log.d("ggp", "hello handler")
            }
            2 -> {
                Log.d("ggp", "hello handler")
            }
        }
        false
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
    }
}

大家都知道,子线程需要更新UI的时候是需要发送消息给主线程handler,然后处理ui,那么好奇一下这里的handler是怎么与activity 主线程(UI线程)绑定的?
首先好奇一下Activity主线程是啥?
回到ActivityThread中看一下mian是怎么实现的

 public static void main(String[] args) {
        ............
//创建looper
        Looper.prepareMainLooper();
        ...........
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
 //拿到handler
            sMainThreadHandler = thread.getHandler();
        }
       ...............
//进入looper无线循环
        Looper.loop();

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

准备主线程 looper prepareMainLooper

    public static void prepareMainLooper() {
//准备looper
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
//get到looper
            sMainLooper = myLooper();
        }
    }

继续

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
//与上边遥相呼应 这里set,将当前looper set给sThreadLocal
        sThreadLocal.set(new Looper(quitAllowed));
    }

looper构造函数

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

这里new 了一个MessageQueue,设置thread为当前Thread,也就activityThread自己。

继续回到Activity Handler初始化过程。

    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) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
//获取到当前looper
        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();
    }

分析一下,这里获取到当前thead的looper,由于我们activity是跑在主进程,当然获取到的就是主线程的looper,继续想一下我们向handler发送消息,就是发送给了主线程Looper。
当前activity中的UIHandler其实拿到了主线程的Looper然后就可以处理主线程任务啦。

activity可以有多个Handler但是拿到的都是主线程的looper。因为在new Handler的时候就自动绑定了主线程looper。

顺道看一下HandlerThread使用

    private var mHandlerThread: HandlerThread? = HandlerThread("ggpthread")
    fun  test() {
        mGgpHandler = Handler(mHandlerThread!!.looper) {
            when(it.what){
                1 -> {
                    Log.d("ggp", "hello HandlerThread")
                }
            }
            false
        }
    }

使用相当简单,这里需要对比一下HandlerThread,在使用第一要务就是getlooper(),我这里使用kotlin写的demo,java也是一样的。看一下getLooper怎么实现的

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

这里wait,等待mLooper初始化,看一下mLooper初始化:

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

当前Thread run中初始化,并且开始looper循环。
总结一下,初始化HandlerThread之后我们就会调用线程start

上一篇下一篇

猜你喜欢

热点阅读