白羽
2018-09-14
来源 :网络
阅读 1210
评论 0
摘要:本文将带你了解Android应用开发之子线程中更新UI的实例讲解,希望本文对大家学Android有所帮助
本文将带你了解Android应用开发之子线程中更新UI的实例讲解,希望本文对大家学Android有所帮助
前言:
一般都会说Android 的UI 只能在主线程中更新,最新在自启动开发的过程中也碰到这样的问题,这里结合source code详细分析一下。
实例引路:
public class ShowThreadUI extends Activity implements OnClickListener { private static final String TAG = "ShowThreadUI"; private Button mTestButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.show_thread_ui); mTestButton = (Button) findViewById(R.id.show_1); initTestButton(); } private void initTestButton() { mTestButton.setOnClickListener(this); Button show_2 = (Button) findViewById(R.id.show_2); show_2.setOnClickListener(this); Button show_3 = (Button) findViewById(R.id.show_3); show_3.setOnClickListener(this); } private void testShow1() { new Thread(new Runnable() {@Overridepublic void run() { WindowManager windowManager = getWindowManager(); TextView textView = new TextView(getApplicationContext()); textView.setText("test 1"); textView.setTextColor(0x54FF9F); windowManager.addView(textView, new WindowManager.LayoutParams());} }).start(); } private void testShow2() { new Thread(new Runnable() {@Overridepublic void run() { mTestButton.setText("button text changed");} }).start(); } private void testShow3() { new TestThread().start(); } class TestThread extends Thread{ @Override public void run() {Looper.prepare();TextView tx = new TextView(ShowThreadUI.this);tx.setText("show me, show me");tx.setTextColor(0x0000EE);tx.setGravity(Gravity.CENTER);WindowManager wm = ShowThreadUI.this.getWindowManager();WindowManager.LayoutParams params = new WindowManager.LayoutParams( 250, 150, 200, 200, WindowManager.LayoutParams.FIRST_SUB_WINDOW, WindowManager.LayoutParams.TYPE_TOAST, PixelFormat.OPAQUE);wm.addView(tx, params);Looper.loop(); } } @Override public void onClick(View view) { int id = view.getId(); switch (id) {case R.id.show_1: testShow1(); break;case R.id.show_2: testShow2(); break;case R.id.show_3: testShow3(); break;default: break; } }}
1、点击button 1
这个时候会报错:
--------- beginning of crash11-07 06:11:24.118 2296 2398 E AndroidRuntime: FATAL EXCEPTION: Thread-211-07 06:11:24.118 2296 2398 E AndroidRuntime: Process: com.shift.testapp, PID: 229611-07 06:11:24.118 2296 2398 E AndroidRuntime: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()11-07 06:11:24.118 2296 2398 E AndroidRuntime: at android.os.Handler.
从堆栈信息来看最终会在 ViewRootImpl 中的ViewRootHandler 触发错误,先来看下ViewRootHandler:
final class ViewRootHandler extends Handler { @Override public String getMessageName(Message message) {
在构造的时候出错的,来看下Handler 的204行:
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) {final Class 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());} } mLooper = Looper.myLooper(); if (mLooper == null) {throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
可以看到最终原因是Handler 中获取Looper 为null。
重新梳理流程,button 1 点击的时候会新开一个线程,在这个线程里创建了UI,WindowManager在addView 的时候会创建ViewRootImpl,其中的Handler 必须要依赖线程中的Looper,Android异步消息处理线程之----Looper+MessageQueue+Handler?中提到Handler 是运行在创建它的线程中,而每个Handler 中的Looper 需要跟Thread 一一对应,换句话说,就是Thread中的Handler 必须有个跟Thread对应的Looper,而这里显然是为null。
结论,通过WindowManger addView 方式创建UI 的时候,需要伴随着创建Looper,Handler 需要。
2、点击button 2
这个时候会报错:
--------- beginning of crash11-07 06:12:01.827 2422 2471 E AndroidRuntime: FATAL EXCEPTION: Thread-211-07 06:12:01.827 2422 2471 E AndroidRuntime: Process: com.shift.testapp, PID: 242211-07 06:12:01.827 2422 2471 E AndroidRuntime: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7334)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1165)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.view.View.requestLayout(View.java:21999)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.view.View.requestLayout(View.java:21999)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.view.View.requestLayout(View.java:21999)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.view.View.requestLayout(View.java:21999)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.view.View.requestLayout(View.java:21999)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.widget.TextView.checkForRelayout(TextView.java:8531)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.widget.TextView.setText(TextView.java:5394)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.widget.TextView.setText(TextView.java:5250)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at android.widget.TextView.setText(TextView.java:5207)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at com.shift.testapp.ShowThreadUI$2.run(ShowThreadUI.java:55)11-07 06:12:01.827 2422 2471 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764)
在ViewRootImpl requestLayout 的时候会调用checkThread:
?123456void checkThread() { if (mThread != Thread.currentThread()) {throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } }
mThread 现在是创建ViewRootImpl 时候的Thread,而这里Thread.currentThread 现在是当前运行的Thread,上面的button 1 中再WindowManger addView 的时候会创建ViewRootImpl,那在activity 中正常运行情况下是什么时候呢?下面会继续说明的。
结论,线程之前创建的View或者UI,在线程中是无法更新的,只有在创建UI的线程中更新该UI。
3、点击button 3
顺利运行,跟button 1 中流程唯一区别就是添加了Looper,证明了button 1 中说到的结论。
修改实例
在原来实例的基础上,我们进行一个修改
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
喜欢 | 0
不喜欢 | 0
您输入的评论内容中包含违禁敏感词
我知道了

请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号