Activity的onCreate方法里面子线程为何能设置UI界面

这是之前朋友被问的一个面试问题,一般情况下我们都知道Android是不允许子线程更新UI的(通过单线程避免多线程的同步更新问题),但是为什么在onCreate方法里面却可以呢,自己试了一下,在onCreate方法直接new一个子线程并执行类似TextView.setText("Joern")这样的指令,发现的确可以没有报错,其实这个我们分析一下setText的代码就可以发现问题所在。

发现setText里面调用了 checkForRelayout();,而在checkForRelayout方法里面调用了invalidate()这个方法再追踪下去,是invalidate方法调用了ViewGroup.invalidateChild,最终调用ViewRootImpl.checkThread()。ViewRootImpl是一个隐藏类,我们只能去看framework的源码,源码如下:

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

mThread是UI线程,这里会检查当前线程是不是UI线程。那么为什么onCreate里面没有进行这个检查呢。这个问题原因出现在Activity的生命周期中,在onCreate方法中,UI处于创建过程,对用户来说界面还不可视,直到onStart方法后界面可视了,再到onResume方法后界面可以交互,。


从某种程度来讲,在onCreate方法中进行setText不能算是更新UI,只能说是配置UI,或者是设置UI的属性。这个时候并不会调用invalidate,也就是不会调用到ViewRootImpl.checkThread()。而在onResume方法后,ViewRootImpl才被创建。这个时候去交互界面以及算是更新UI了,这个时候ViewRootImpl.checkThread()就会报错了

网上还有一个试的方法,就上把上面onCreate的更新线程延迟200ms,这样onResume执行完成了,也的确会报错了

Thread thread = new Thread("Thread1") {
			public void run() {
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				tv.append( System.currentTimeMillis() + "\n");
				tv.append("thread name:" + Thread.currentThread().getName());
				iv.setImageResource(R.drawable.ic_launcher);
			};
		};
		thread.start();





  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值