美文网首页
android主线程与Handler

android主线程与Handler

作者: 丸子不爱吃丸子 | 来源:发表于2019-10-30 09:41 被阅读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

    相关文章

      网友评论

          本文标题:android主线程与Handler

          本文链接:https://www.haomeiwen.com/subject/ahagvctx.html