美文网首页
关于子线程能否更新UI的思考

关于子线程能否更新UI的思考

作者: WhenMeet | 来源:发表于2018-11-22 11:12 被阅读92次

关于子线程能否更新UI的思考

线程通讯详解

线程池-多线程的高效使用姿势

        当大家被问到这个问题的时候可能就很迷茫了

        谁没事干这样做呢?

        但是今天我们只关注能不能。

        说到这个问题,我们就不能提一下什么是UI线程,UI线程也叫主线程,为什么这么说呢?

        因为当Activity被创建后,我们布局的实现都由系统分配的一个线程(其实就是一个普通的线程)进行刷新,但是就因为这个线程做了刷新UI这个操作,所以被称之为UI线程,自此,除此之外的线程都自动被称之为子线程。

        就有人要问了,你说什么啊?不是说子线程不能更新UI么,你这怎么界面是由一个普通线程进行刷新的呢?

        其实这样的理解是对的,但是我这里还是要详细解释一下,UI是可以被线程更新的,当Activity被创建后,布局也被选中的这个线程刷新后,才有了主线程和子线程的概念,那么刚才提出的问题:子线程不能更新UI?这里就要提出一个View更新的原则,由谁创建,由谁更新,既然界面已经由一个线程(主线程)创建了,那么刷新就必定要在这个线程中进行刷新,所以才有了大家认定的结论,不过不要紧,我们其实在子线程中也能更新UI,因为View更新的原则是由一个ViewRoot类提供的,当我们在子线程中进行操作界面的时候会被ViewRoot进行检查一番:

void checkThread() {

    if (mThread != Thread.currentThread()) {

        throw new CalledFromWrongThreadException(

                "Only the original thread that created a view hierarchy can touch its views.");

    }

}

        大概就是这样,当发现创建的新线程和当前的线程不是同一线程时就会抛出异常,但是大家不用担心,因为ViewRoot的创建是在Activity的onResume中的,所以说,当我们在这个生命周期之前用子线程更新UI就是可行的,但是这么一看,这种操作貌似就像是钻了空子一样,那么还有一个例子可以举,Toast大家应该不陌生,那么Toast的调用能不能在子线程中呢?这个问题看起来就像是和前面的问题一样,当我们去做的时候,系统是会抛出异常的:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

        这个问题大家可能也见过,从字面意思我们可以知道,我们的Looper还没有准备好,说到这里,我又不得不提一下子线程去界面的刷新流程了,大概涉及以下几个概念:

Message、Handler、MessageQueue、Looper

        这几个概念大家应该比较熟悉,但是我还是稍微解释以下,Message是消息载体,Handler是消息处理类,MessageQueue是存储消息的队列(也就是Message),Looper则是处理MessageQueue的工具,会不断的遍历MessageQueue,每当检查存在消息时就会取出来发送给Handler进行处理,那么这几个概念理清了,我们接着上面的问题,子线程调用Toast抛出的异常,那么这个问题我们可以反转一下,为什么在主线程调用就不会有异常呢?大家看了我上面说了子线程刷新界面的流程有没有思路了呢?

        就是因为当Activity创建的时候,创建布局线程的Looper也被调用了,已经在工作中了,但是我们新创建的线程却没有准备的好,所以会提示上面的错误,当我们调用以下代码:

                    Looper.prepare();

                    Looper.loop();

        并放在Toast的前后就可以让新创建的线程里面的Looper正常工作了。

        那么同学有疑问了,那我不用Toast,换成其他更新UI的代码行不行?

        回答可能让你失望了,不行!这是因为Toast的创建和我们普通界面的创建是有区别的,Toast的创建我们去查看一下就知道,是通过NotificationManager调用系统的WindowManager实现的,在这里我稍微说一下,我们所看到的界面实际上是由俩部分组成的,一个是View和它的子类,一个就是WindowManager,到这里就知道创建Toast时,使用的线程并不是主线程,所以我们可以这样操作,但是普通的布局就不行了。

        但是有人可能就去试验了,咦?我的测试了在子线程可以更新UI哎!?

         楼主!你写的啥,咋不对呢?

        别紧张,其实面对不同的机型,得到的答案可能都会有或多或少的变化,因为并不能排除部分开发商对机型源码的修改和安卓Sdk不同版本的代码改动,我就遇到子线程调用Toast,既不报错也不展示的情况,所以,我们需要知道最基本的一个过程是什么样子,那么当下次有人问你这个问题的时候,最好的回答是不是:看源码你不就知道了?

        好了,到这里大家应该对子线程能不能更新UI有了更新的认识了吧,下期再见。

相关文章

  • 线程通讯详解

    关于子线程能否更新UI的思考线程通讯详解线程池-多线程的高效使用姿势 上文我们说到了关于子线程中能否更新UI的问题...

  • 关于子线程能否更新UI的思考

    关于子线程能否更新UI的思考 线程通讯详解 线程池-多线程的高效使用姿势 当大家被问到这个问题的时候可能就...

  • 线程池-多线程的高效使用姿势

    关于子线程能否更新UI的思考线程通讯详解线程池-多线程的高效使用姿势 在开始这个话题之前我觉得还是得先谈一谈什么是...

  • 如何做到在子线程更新 UI?

    一般来讲,子线程是不能更新 UI 的,如果在子线程更新 UI,会报错。 但在某种情况下直接开启线程更新 UI 是不...

  • Android在线程中更新UI和在协程中更新UI

    1、在子线程里面更新UI 我们都知道Android只能在主线程里面对UI更新,所以谷歌提供了很多在子线程里面更新U...

  • 子线程更新UI的方法

    子线程中不能直接更新UI,如果直接更新的话会发生崩溃所以要在主线程中更新UI,总计三种回到主线程更新UI的方式 1...

  • 非UI线程是否可以更新UI

    可以,在onCreate函数子线程是可以更新UI的因为通常的子线程更新UI的报错是ViewRootImpl类的ch...

  • 【Android】AsyncTask源码分析

    在Android中ui是非线程安全的,更新ui只能在主线程操作,所以我们平时如果遇到子线程更新UI的情况,必须要切...

  • Android多线程

    1.沿用java的子线程创建 2.在子线程中不能更新UI,那么在Android中更新UI的方法 runOnUiTh...

  • Android 关于子线程更新UI的那些事

    一 相信大家都有听过,子线程更新UI的操作。但这种说法,不是很明确。有些人说子线程更新UI会挂,而有些人说子线程可...

网友评论

      本文标题:关于子线程能否更新UI的思考

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