android UI线程安全问题
在Android的子线程去更新UI的内容,会导致不确定的异常。
因为Android有个模式是,单一线程模型:Android UI工具箱(toolkit)不是一个线程安全的,并且它总是被放在主线程上操作。
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}
首先,从上面代码看上去好像非常完美,因为它不会阻塞UI线程,不幸的是,它违背了单一线程模型:Android UI工具箱(toolkit)不是一个线程安全的,并且它总是被放在主线程上操作。
- Activity.runOnUiThread(Runnable)
- View.post(Runnable)
- View.postDelayed(Runnable, long)
- Handler
以上任何一种方式都能修正我们的代码:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}
当然我们还有更简单的方法,使用AsyncTask
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<string, integer, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
package vic.wong.main;
import android.os.AsyncTask;
import android.widget.ProgressBar;
import android.widget.TextView; /**
* 生成该类的对象,并调用execute方法之后
* 首先执行的是onProExecute方法
* 其次执行doInBackgroup方法
*
*/
public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {
private TextView textView;
private ProgressBar progressBar;
public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {
super();
this.textView = textView;
this.progressBar = progressBar;
}
/**
* 这里的Integer参数对应AsyncTask中的第一个参数
* 这里的String返回值对应AsyncTask的第三个参数
* 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改
* 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作
*/
@Override
protected String doInBackground(Integer... params) {
NetOperator netOperator = new NetOperator();
int i = 0;
for (i = 10; i <= 100; i+=10) {
netOperator.operator();
publishProgress(i);
}
return i + params[0].intValue() + "";
} /**
* 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
* 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置
*/
@Override
protected void onPostExecute(String result) {
textView.setText("异步操作执行结束" + result);
}
//该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
@Override
protected void onPreExecute() {
textView.setText("开始执行异步线程");
}
/**
* 这里的Intege参数对应AsyncTask中的第二个参数
* 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
* onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作
*/
@Override
protected void onProgressUpdate(Integer... values) {
int vlaue = values[0];
progressBar.setProgress(vlaue);
}
}
android UI线程安全问题的更多相关文章
- Android UI线程和非UI线程
Android UI线程和非UI线程 UI线程及Android的单线程模型原则 当应用启动,系统会创建一个主线程(main thread). 这个主线程负责向UI组件分发事件(包括绘制事件),也是在这 ...
- 有关android UI 线程
1. GUI线程框架 常见的 Swing, SWT框架都是作为单线程子系统来实现的,实际上不仅限于在Java中, Qt.MacOS Cocoa以及其他的环境中的GUI框架都是单线程的.虽然很多人尝试过 ...
- android脚步---如何看log之程序停止运行,和UI线程和非UI线程之间切换
经常运行eclipse时,烧到手机出现,“停止运行”,这时候得通过logcat查log了.一般这种情况属于FATAL EXCEPTION,所以检索FATAL 或者 EXCEPTION,然后往下看几行 ...
- android 在非UI线程更新UI仍然成功原因深入剖析
”只能在UI主线程中更新View“. 这句话很熟悉吧? 来来,哥们,看一下下面的例子 @Override protected void onCreate(Bundle savedInsta ...
- Android子线程真的不能更新UI么
Android单线程模型是这样描述的: Android UI操作并不是线程安全的,并且这些操作必须在UI线程执行 如果在其它线程访问UI线程,Android提供了以下的方式: Activity.run ...
- Android子线程更新UI主线程方法之Handler
背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. ...
- [原] Android performClick无效,UI线程理解
原因 开发过程中遇到button.performClick()无效,原因是View.performClick()需要再UI线程中调用才会有效执行. 响应系统调用的方法(比如报告用户动作的onKeyDo ...
- 【Android开发学习笔记】【随笔】UI线程
概念 UI线程 是Android中的主线程,涉及到UI方面的一些操作都需要在ui线程中进行操作 在非ui线程中想操作ui,就会报错 android.view.ViewRoot$CalledFromWr ...
- Android ActivityThread(主线程或UI线程)简介
1. ActivityThread功能 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client ...
随机推荐
- ant脚本
jenkins在调用ant脚本时会遇到ant中的目标没有成功,但是最后的build状态却是success,如下图所示:代码中缺少一个},编译发生错误,最后的build成功. 解决方案:在关键的targ ...
- hdu1285 确定比赛名次(拓扑排序)
确定比赛名次 Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total Submis ...
- js date相关学习!
var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1970-???? ...
- 双重检查锁定与延迟初始化(转自infoq)
很好的文章,转自http://www.infoq.com/cn/articles/double-checked-locking-with-delay-initialization 在java程序中,有 ...
- zencart hosts本地解析
C:\WINDOWS\system32\drivers\etc\hosts 127.0.0.1 www.aberc220.com 别人 192.168.1.64 www.aberc220.com ...
- startActivityForResult相关的
在Fragment里调用startActivityForResult,界面回来后,会先走其宿主Activity的onActivityResult方法,再走Fragment的. 在Fragment里面嵌 ...
- typedef void far *LPVOID 的具体定义
首先这里的far,在32位系统已经废除不用了.它是C/C++语言在16位系统中用以标明指针是个远指针的修饰符. 远指针是说指针所指向的地址已经超出了64K(2的十六次方),所以需要使用DS加偏移量的方 ...
- 表单提交中记得form表单放到table外面
帝国后台按栏目搜索文章时怎么都不生效 控制台查看原来是 栏目的select的值没有提交过去,原来由于form标签在table标签里面,导致js生成的<select>标签提交失败. 解决办 ...
- java.lang.ClassCastException: com.sun.proxy.$Proxy8 cannot be cast to com.bjsxt.service.UserServiceImpl01_AOP.
对于Spring AOP 采用两种代理方法,一种是常规JDK,一种是CGLIB,我的UserDao了一个接口IUserDao,当代理对象实现了至少一个接口时,默认使用 JDK动态创建代理对象,当代理对 ...
- css float left right 中间空间城数据无法显示
css float left right 中间空间城数据无法显示 是由于设定了width具体值太小造成,简单用%值或不设置.