首页 > 代码库 > android UI线程安全问题
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)不是一个线程安全的,并且它总是被放在主线程上操作。
这个ImageView被一个工作线程操作,这导致非常不可思议的问题。跟踪和修复这样一个bug很难并且也耗时。
Android提供了几种从其他线程访问主线程的方式:
- 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
不幸的是,这些类和方法导致我们的代码变得复杂和可读性差。当你实现复杂的操作来频繁的更新界面,使用这种方式变得更加糟糕。为了解决这个问题,Android1.5提供了一个公共类叫做AsyncTask,它简化了任务线程和主线程之间的通信。
在Android1.0和1.1也可使用AsyncTask只不过它的名字为UserTask。
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); } }
AsyncTask通过它的子类才能使用。要记住,一个AsyncTask实例必须在主线程创建并且只能被执行一次。完全理解和使用这个类,你可以阅读AsyncTask文档。这里快速的说一下AsyncTask是怎么工作的:
1>可以通过泛型指定它的类型:参数,进度值,任务的结果值。
2>doInBackGround()方法自动在工作线程中只想能够。
3>onPreExecute(),onPostExecute(),onProgressUpdate()方法都在UI线程中执行。
4>doInBackground()方法返回的值被当作参数传递给onPostExecute()方法。
5>你能够在doInBackground()方法里任何时候调用publishProgress()方法在UI线程中去执行onProgressUpdate()方法。
下面写一个重载方法比较多得类:
1 package vic.wong.main; 2 import android.os.AsyncTask; 3 import android.widget.ProgressBar; 4 import android.widget.TextView; 5 6 /** 7 * 生成该类的对象,并调用execute方法之后 8 * 首先执行的是onProExecute方法 9 * 其次执行doInBackgroup方法10 *11 */12 public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {13 private TextView textView;14 private ProgressBar progressBar;15 public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {16 super();17 this.textView = textView;18 this.progressBar = progressBar;19 }20 /**21 * 这里的Integer参数对应AsyncTask中的第一个参数 22 * 这里的String返回值对应AsyncTask的第三个参数23 * 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改24 * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作25 */26 @Override27 protected String doInBackground(Integer... params) {28 NetOperator netOperator = new NetOperator();29 int i = 0;30 for (i = 10; i <= 100; i+=10) {31 netOperator.operator();32 publishProgress(i);33 }34 return i + params[0].intValue() + "";35 }36 37 /**38 * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)39 * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置40 */41 @Override42 protected void onPostExecute(String result) {43 textView.setText("异步操作执行结束" + result);44 }45 //该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置46 @Override47 protected void onPreExecute() {48 textView.setText("开始执行异步线程");49 }50 /**51 * 这里的Intege参数对应AsyncTask中的第二个参数52 * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行53 * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作54 */55 @Override56 protected void onProgressUpdate(Integer... values) {57 int vlaue = values[0];58 progressBar.setProgress(vlaue);59 }60 }
android UI线程安全问题
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。