Android子线程中更新UI的方法
2016-12-29 15:17
411 查看
1.handler
2.通过runOnUiThread方法
方法内部实现如下:public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } }使用方法如下:
new Thread(new Runnable() { @Override public void run() { // 此处执行耗时操作,结束后,执行runOnUiThread将线程切换到主线程去更新ui runOnUiThread(new Runnable() { @Override public void run() { // 更新ui操作 } }); } }).start();如果在非上下文中环境中,可以通过一下方法来实现:
final Activity activity = (Activity) mTextView.getContext(); new Thread(new Runnable() { @Override public void run() { activity.runOnUiThread(new Runnable() { @Override public void run() { } }); } }).start();
在其他地方,则需要传递Activity对象,因为runOnUiThread方法是Activity的方法。
3.通过view.post(runnable)来实现
mTextView.post(new Runnable() { @Override public void run() { } });
以上不管哪种方法,原理都是将更新ui的消息从子线程中传递到主线程中,因为,更新view只能在主线程,这个是无法改变的。
4.子线程直接更新ui的极端情况
android的UI访问是没有加锁的,这样会导致多个线程访问ui会不安全,那么既然这样,为什么不加锁呢,因为加上锁机制会让ui访问的逻辑变得复杂,其次锁机制会降低ui访问的效率,锁机制会阻塞某些线程的执行。所以android规定,只能在主线程更新ui。子线程真的无法更新ui吗,答案是no,因为有些极端情况,还是可以更新ui的。
我们在onCreate中直接执行以下代码:
Log.i("niejianjian", " -> onCreate -> " + Thread.currentThread().getId()); new Thread(new Runnable() { @Override public void run() { Log.i("niejianjian", " -> Thread -> " + Thread.currentThread().getId()); mTextView.setText("fjsdlj l"); } }).start();发现更新ui是可以成功的,我们可以打印当前的线程,发现确实是在子线程中,因为主线程的id是1。但是我们在将Thread睡眠200ms,
Log.i("niejianjian", " -> onCreate -> " + Thread.currentThread().getId()); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } Log.i("niejianjian", " -> Thread -> " + Thread.currentThread().getId()); mTextView.setText("fjsdlj l"); } }).start();结果就报错了,log如下:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6257) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:868)ViewRootImpl是ViewRoot的实现类,异常主要是checkThread抛出的,因为里面对线程做了判断:
void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } }因为view的绘制过程中,都会执行ViewRootImpl的checkThread来检查是否是主线程更新,所以onCreate中的子线程可以更新ui,主要是因为ViewRootImpl还没有创建,所以无法进行检查。
ViewRootImpl的创建在onResume方法回调之后,而我们一开篇是在onCreate方法中创建了子线程并访问UI,在那个时刻,ViewRootImpl是没有创建的,无法检测当前线程是否是UI线程,所以程序没有崩溃一样能跑起来,而之后修改了程序,让线程休眠了200毫秒后,程序就崩了。很明显200毫秒后ViewRootImpl已经创建了,可以执行checkThread方法检查当前线程。
参考:http://www.cnblogs.com/xuyinhuan/p/5930287.html
相关文章推荐
- Android子线程中更新UI的3种方法
- Android子线程更新UI的方法
- Android子线程中更新UI的三种方法和获取message的两种方法总结
- Android子线程中更新UI的3种方法
- Android子线程更新UI的方法总结
- Android子线程中更新UI的3种方法
- Android子线程中更新ui的方法
- Android 子线程操作更新UI方法
- 非UI线程更新UI界面的各种方法小结
- C# Winform 跨线程更新UI控件常用方法汇总
- WPF跨线程更新UI的3种方法
- C#线程更新UI的方法
- .NET一个线程更新另一个线程的UI(两种实现方法及若干简化)
- Android在子线程中更新Activity中UI的方法
- 子线程更新UI会发生android.view.ViewRoot$CalledFromWrongThreadException异常的解决方法
- Android学习笔记-转载两篇关于线程更新UI的方法的文章
- 子线程更新UI会发生android.view.ViewRoot$CalledFromWrongThreadException异常的解决方法 .
- Silverlight中 非UI线程更新UI 的几种方法
- 线程里更新UI的两种方法:Thread+Handler和Runnable
- 子线程更新UI的方法