精华内容
下载资源
问答
  • 众所周知在Android中,子线程是不能更新UI的; 那么我在想,为什么不能,会产生什么问题; 是否真的就一定不能在子线程更新UI; 2、能否在子线程中更新UI 答案是可以的。 ViewRootImpl对象是在onResume方法回调...

    1、前言

    • 众所周知在Android中,子线程是不能更新UI的;
    • 那么我在想,为什么不能,会产生什么问题;
    • 是否真的就一定不能在子线程更新UI;

     

    2、能否在子线程中更新UI

    答案是可以的。

    ViewRootImpl对象是在onResume方法回调之后才创建,那么就说明了为什么在生命周期的onCreate方法里,甚至是onResume方法里都可以实现子线程更新UI,因为此时还没有创建ViewRootImpl对象,并不会进行是否为主线程的判断;

     

    3、更新UI一定要在主线程实现

    谷歌提出:“一定要在主线程更新UI”,实际是为了提高界面的效率和安全性,带来更好的流畅性;反推一下,假如允许多线程更新UI,但是访问UI是没有加锁的,一旦多线程抢占了资源,那么界面将会乱套更新了,体验效果就不言而喻了;所以在Android中规定必须在主线程更新UI


    4、总结

    • 子线程可以在ViewRootImpl还没有被创建之前更新UI
    • 访问UI是没有加对象锁的,在子线程环境下更新UI,会造成不可预期的风险;
    • 开发者更新UI一定要在主线程进行操作;



    作者:绿茵场上的码者
    链接:https://www.jianshu.com/p/58c999d3ada7
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

     

    展开全文
  • https://www.jianshu.com/p/29e75093f5a2
    展开全文
  • 更新UI是必须要主线程(ui线程)来更新的,即UI线程更新。如果在主线线程之外的线程中直接更新页面显示会报错。  记住!:只有原始创建这个视图层次(view hierachy)的线程才能修改它的视图(view) Handler的定义:...

    前言

    ————————————————————————————————————————————————————

    为什么Andorid不能更新子线程更新UI?这里我们从几个方面来探究;

    ———————————————————————————————————————————————————

    1:Android开发人员设计角度


    由于Android是典型的GUI(图形用户界面)模型,而现代GUI模型都是单线程设计思想(读者可自行查询相关资料)。大意就是为了避免获取数据时候的竞争导致死锁。多线程问题已经够麻烦了,如果GUI也设计程多线程,肯定是会更加麻烦。


    2:SDK源码角度


    1:如果子线程更新了UI,我们会得到异常提示,跟进异常抛出类查看,此方法是ViewRootImpl类内部的方法:

    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

    通过mThread 与 Thread.currentThread()相等来判断是否异常,,

    所以重点来了Thread.currentThread()是当前线程,那么mThread是什么线程呢?


         2:我们跟进查看构造方法

    public ViewRootImpl(Context context, Display display) {
        ......
    
        mThread = Thread.currentThread();
        ......
    }
    知道当ViewRootimpl第一次构造时候就分发给了我们一个currentThread(). 那么创建ViewRootimpl与更新checkThread的线程就必须是一样的才不会有异常。那么我们创建ViewRootImpl的线程是什么线程呢?如下分析


    ViewRootImpl分析
    官方对于此类解释:

    The top of a view hierarchy, implementing the needed protocol between View* and the WindowManager.
     This is for the most part an internal implementation* detail of {@link WindowManagerGlobal}.

    
    
    
    

    ViewRootImpl他是View树的顶级视图,但它却又不是View,只是实现了View与WindowManager之间的通信协议(2.2版本之前使用ViewRoot此后版本更改为ViewRootImpl)。

    这里我们要了解就是ViewRootImpl并不是一个View,只是一个将View与WindowManager关联起来的类;分析得:ViewRootImpl也是依附于View与windowManager存在的,再通过此ViewRootImpl类注释分析:就是WindowManagerGlobal具体细节上的一个内部实现“This is for the most part an internal implementation detail of @link WindowManagerGlobal” ——————>跟进

    WindowManagerGlobal分析:

    通过官方注释得

    这个类的关系:是底层类与窗口之间的上下文联系类,我们并不需要使用它,直接使用WindowManager;

    类注释叫我们 see windowmanager

    WindowManager与windowManagerimpl

    然而WindowManager是一个接口 实现了ViewManager,ViewManager也是一个接口。

    所以我们要看其实现类 windowMangerImpl,

    WindowManagerImpl并没有实现WindowManager的三大操作,而是全部交给WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供自己的实例。就是说WindowManagerImpl将所有的操作全部委托给WindowManagerGlobal来实现。这是一种桥接模式。

    通过windowManagerImpl发现其内部就是对WindowManagerGlobal 的封装,各种addview,removeview之类的调用本意就是WindowManagerGlobal 的调用如

    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
     @Override
        public void removeView(View view) {
            mGlobal.removeView(view, false);
        }
    @Override
     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.addView(view, params, mDisplay, mParentWindow);
        }

    
    ViewManager分析
    

    ViewManager就一个简单的接口,定义了addview,removeview,updateview,三个方法,

    小结

    通过一系列的跟源码与分析大致流程:ViewManager  -->> WindowManager(继承自ViewManager) -->> WindowManagerImpl(继承自WindowManager) -->>WindowManagerGlobal(暴露实例给WindowManagerImpl调用处理) -->> ViewRootImpl (WindowManagerGlobal的内部具体细节实现)

    接下来简单分析Activity的启动

    Activity的其实很复杂的,本人也不是完全理解但是我们抓住其入口ActivityThread类即可 (android.app.ActivityThread

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) { 
        //...
        ActivityClientRecord r = performResumeActivity(token, clearHide); // 这里会调用到onResume()方法
    
        if (r != null) {
            final Activity a = r.activity;
    
            //...
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow(); // 获得window对象
                View decor = r.window.getDecorView(); // 获得DecorView对象
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager(); // 获得windowManager对象
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l); // 调用addView方法
                }
                //...
            }
        }
    }
    根据注释可以看到:回调onResume方法后  内部得到windowmanager与Window并且addView,加入了一个Decorview,

    总结

    我们开发是基于Activity,activity的setcontentview一执行 ,系统就给与了我们一个基础的window视图PhoneWIndow实例,

    PhoneWindow内部就管理了一个顶级View,DecorVew,层级如图


    我们之后的操作都是建立在DecorView上来实现UI的更新。因为创建最顶级DecoView是ActivityThread的window.add进来的,同时因为ViewRoolImpl管理DecoView与window窗体之间的联系,所以DecoView任何子视图ViewRoolImpl的currentThread()其实就是ActivityThread(UI线程),当在非UI线程更新时候checkThread()就出现错误。(有点拗口但是道理就是这么个道理。)

    延伸:::

    1:子线程不能更新UI是错误的,严格意义上讲是(只有创建了View的顶级父视图的线程才能更新UI。其他线程不能干预,干预了ViewRootImpl就给你异常错误提示,目的是为了避免GUI多线程的其他错误)。

    2:子线程如果在onResume之前更新UI(onCreate时候),此时的view只是一个对象还没有与phonewindow之间建立联系。所以可以更新。 但是onResume之后也就是View被主线程添加进window后,ViewRoolImpl此类就能管理view与window之间的联系,此时其他线程不能干预了。


    展开全文
  • 子线程中是不能进行UI 更新的,而可以更新的结果只是一个幻像:因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI更新的函数栈,这中间的时间非常的短,就 让大家误以为分线程可以更新UI。...

    在子线程中是不能进行UI 更新的,而可以更新的结果只是一个幻像:因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI更新的函数栈,这中间的时间非常的短,就 让大家误以为分线程可以更新UI。如果子线程一直在运行,则子线程中的UI更新的函数栈 主线程无法获知,即无法更新

     

    参考:http://blog.sina.com.cn/s/blog_45e2b66c0102v254.html

    转载于:https://www.cnblogs.com/damonWq/p/5361247.html

    展开全文
  • 子线程中是不能进行UI 更新的,而可以更新的结果只是一个幻像:因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI更新的函数栈,这中间的时间非常的短,就让大家误以为分线程可以更新UI。...
  • 大家都知道,在子线程中直接更新UI就会奔溃,报错如下: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 报错提示:...
  • 为什么子线程不能直接更新UI

    千次阅读 2019-12-05 11:48:28
    点击上方“dotNET全栈开发”,“设星标”加“星标★”,每天11.50,好文必达全文约4000字,预计阅读时间8分钟当初有同事就碰到类似的问题,于是就总结了一些,那时写这篇文章是我还...
  • 为什么不能子线程更新UI

    千次阅读 2016-11-04 00:09:08
    1、在子线程中是不能进行UI 更新的,而可以更新的结果只是一个幻像:因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI更新的函数栈,这中间的时间非常的短,就让大家误以为分线程可以更新UI。...
  • 在Android子线程中初始化handler后,然后初始化looper,使得该子线程具有消息处理机制...子线程的hanlder里面是不能更新Android UI的。 简单说下: 如果你在子线程里面创建hander是用的是以下代码: n
  • 为什么不能子线程更新UI 看了以上文章后,做一些补充 同样的,我们还可以猜测,在onStart方法和onResume方法里面创建子线程并访问更新UI,同样是可以运行成功的。这一点留给读者去验证。 在onCreate()写如下...
  • 而是更新UI的方法不是线程安全的,即只能在单线程中完成UI的更新,不能使用多线程。(为什么呢?因为子线程可能会有多个,存在多个线程同时操作一个控件的情况)因此,只能在主线程中进行UI更新。 1...
  • 那么为什么在Android中子线程不能更新UI呢? 下面我从自己写的一个demo中来一步一步分析 案例 新建一个工程,给TextView增加一个id属性 tv,连接真机运行显示如下图片 在MainActivity中的OnCreate方法中,做以下...
  • 1. 为什么不能子线程更新UI ? 一般我们在项目中,进行联网请求后,这里我们就用子线程来表示联网请求,开了线程后获取到我们服务器返回的数据后,需要去更新UI,在这里我们就需要去调用setText()、setImageView...
  • 为什么Google要规定不能在子线程不能更新UI呢:  首先UI线程(mainThread)并不是线程安全的,这样如果子线程修改UI容易数据错乱,如果做到线程安全的话,这样做是很低效的。其次谷歌推荐如果子线程需要修改...
  • 首先声明一点:子线程里面是可以更新UI的——创建一个空白的Activity,在其xml文件中放一个空白TextView,Java代码如下: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate...
  • 初学android一段时间,经常我们会听到说不能在子线程更新UI不能在主线程执行耗时操作,但是谁知道这到底是为什么呢? 难道子线程一点UI都不能操作吗?若在子线程操作UI会出现什么问题呢? 还有android(java)...
  • 子线程为什么不能更新UI

    千次阅读 2016-05-09 00:07:12
    安卓允许子线程更新UI是因为UI访问是没有加锁的,多个线程访问UI不是线程安全的   由源码可知,检测ui更新是否在主线程的操作是在Activity的OnResume方法中执行的 如果在子线程立刻访问ui,此时还没走到OnResume...
  • 当你打开这个文档的时候,你已经做好准备了,话多说开搞。 本文以Android 9.0 版本进行分析,当然你也可以在线看源码 在线源码查看 Android源码下载编译 9.0源码百度网盘下载链:...
  • 平时我们在开发过程中知道主线程不能进行耗时操作,子线程不能更新UI,于是有了线程间通讯,有了Handler机制,那么子线程真的不能更新UI么?很多小伙伴在面试的时候也会经常被问到这个问题,网上已经有了不少详解这...
  • 1、在子线程中是不能进行UI 更新的,而可以更新的结果只是一个幻像:  因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI更新的函数栈,这中间的时间非常的短,就让大家误以为分线程可以更新UI...
  • - (void)touchesBegan:(NSSet<... //注意: 所有网络操作不能直接写在主线程中 因为所有的网络操作都是耗时的,如果加载到主线程中,会导致与用户的交互出现问题 ,所以要加载到子线程中 // [self loadImage]; [...
  • 为什么不能子线程更新UI?如果在子线程更新UI会怎样? 为了模拟在子线程更新UI的场景,简单地写了几行代码: @Override protected void onCreate(Bundle savedInstanceState) { super.onC
  • 从Android开发的第一课开始,我们就有一个常识,即子线程不能更新UI,只能在转到主线程去更新?所以我们在编码时都遵照着这个原则,获取到数据后通过handler去转到主线程,通过Message拿到子线程发送过来的数据,...
  • 作者:北斗星_And来源:...为什么子线程不能更新UI?是不是子线程一定不可以更新UI?SurfaceView是为什么可以直接子线程绘制呢?用SurfaceView 做一个小游戏,别踩百块,so easy!今天我们来一起讨论一下这...
  • 在 iOS开发过程中,我一直知道更新UI需要在主线程中,但也没怎么细想为什么要在主线程中,或者说为什么不能子线程更新UI。 像UIKit这样大的框架上确保线程安全是一个重大的任务,会带来巨大的成本。UIKit不是...
  • Android的主线程的确不能长时间阻塞,但是子线程为什么不能更新UI呢?今天把这些东西整理,顺便在子线程更新UI。  首先写了一个handler在子线程更新主线程UI,在子线程做了一个耗时操作:从网络下载了一个图片并...
  • 是因为UI线程是用来刷新界面的,会通过Android的invalidate()方法去刷新界面,但是invalidate不能再非UI线程去调用(原理就是你通过其他线程去调用这个方法,而UI线程也在调用这个方法,所以就会导致线程不安全了,...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 178
精华内容 71
关键字:

为什么子线程不能更新ui