子线程更新ui java_子线程可以更新UI吗

尝试直接在子线程中更新text

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

var text: TextView = findViewById(R.id.text)

Thread(Runnable {

text.text = "can I change you?"

}).start()

}

47bbf6f2f9fc

image.png

可以看到界面正常展示,textView的内容被更新且没有crash.

那我们就能得出可以在子线程中随意更新UI的结论了吗?

在thread中加上延时呢?

Thread(Runnable {

Thread.sleep(300)

text.text = "can I change you?"

}).start()

运行,竟然崩溃了。。

2020-08-09 10:55:51.895 26802-26858/com.drinkwater.meng.myapplication E/AndroidRuntime: FATAL EXCEPTION: Thread-2

Process: com.drinkwater.meng.myapplication, PID: 26802

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753)

at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1225)

at android.view.View.requestLayout(View.java:23093)

at android.view.View.requestLayout(View.java:23093)

at android.view.View.requestLayout(View.java:23093)

at android.view.View.requestLayout(View.java:23093)

at android.view.View.requestLayout(View.java:23093)

at android.view.View.requestLayout(View.java:23093)

at androidx.constraintlayout.widget.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)

at android.view.View.requestLayout(View.java:23093)

at android.widget.TextView.checkForRelayout(TextView.java:8908)

at android.widget.TextView.setText(TextView.java:5730)

at android.widget.TextView.setText(TextView.java:5571)

at android.widget.TextView.setText(TextView.java:5528)

at com.drinkwater.meng.myapplication.MainActivity

math?formula=onCreate2.run(MainActivity.kt:43)

异常翻译:只有创建这个view的线程才能操作这个view!

注意此时我们的子线程都在oncreate中,那如果放在onresume中呢?

override fun onResume() {

super.onResume()

Thread(Runnable {

// Thread.sleep(300) 放在onResume中后,不加延迟不会崩溃,加延时的话,延时短的情况下偶尔崩溃,长的话必崩

text.text = "can I change you?"

}).start()

Log.d("TAG", "onResume()")

}

为什么加了长延迟,就必崩呢?

看下崩溃的堆栈,发现是在ViewRootImpl.requestLayout的时候checkThread 方法中检查线程

@Override

public void requestLayout() {

if (!mHandlingLayoutInLayoutRequest) {

checkThread();

mLayoutRequested = true;

scheduleTraversals();

}

}

void checkThread() {

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

throw new CalledFromWrongThreadException(

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

}

}

//那这个mThread又是什么时候赋值的呢?

public ViewRootImpl(Context context, Display display) {

...

mThread = Thread.currentThread();

....

}

//可以看出mThread是在ViewRootImpl初始化的时候赋值的,那ViewRootImpl初始化是什么时候呢?其实在onResume时,最终会调用到WindowManagerGlobal.addView()之中。而这里也就可以看ViewRootImpl的“管理逻辑”:

public final class ActivityThread {

@Override

public void handleResumeActivity(...){

//...

windowManager.addView(decorView, windowManagerLayoutParams);

}

}

//WindowManagerImpl.java

public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow){

...

//初始化ViewRootImpl的地方

ViewRootImpl root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);

mRoots.add(root);

mParams.add(wparams);

//最终调用ViewRootImpl.setView开始刷新绘制View

root.setView(view, wparams, panelParentView);

...

}

由于ViewRootImpl初始化是在onResume 中调用的,也就是在主线程调用,因此ViewRootImpl的mThread在onResume后才被赋值,因此之后子线程中更新text,调用到requestLayout的时候检查线程就会异常崩溃。

在onCreate中子线程不加延时不崩溃是因为此时ViewRootImpl还没完成初始化,还没开始绘制,绘制是在onresume中调用了ViewRootImpl.setView之后开始的,就会把绘制之前对view设置的属性进行绘制。

进阶

ViewPropertyAnimator Android 5.0之后通过RenderThread实现异步layout,

measure 从而实现异步动画。只能通过反射使用

ViewPropertyAnimator animator = clickTest.animate().scaleX(4).setDuration(2000);

setViewPropertyAnimatorRT(animator,createViewPropertyAnimatorRT(clickTest));

animator.start();

private static Object createViewPropertyAnimatorRT(View view) {

try {

final Class> animRtClazz = Class.forName("android.view.ViewPropertyAnimatorRT");

final Constructor> animRtConstructor = animRtClazz.getDeclaredConstructor(View.class);

animRtConstructor.setAccessible(true);

return animRtConstructor.newInstance(view);

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

private static void setViewPropertyAnimatorRT(ViewPropertyAnimator animator, Object rt) {

try {

final Class> animRtClazz = Class.forName("android.view.ViewPropertyAnimatorRT");

final Field animRtField = animRtClazz.getDeclaredField("mRTBackend");

animRtField.setAccessible(true);

animRtField.set(animator,rt);

} catch (Exception e) {

e.printStackTrace();

}

}

缺点是 使用限制较多,不能使用监听器,不能开启硬件加速等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值