標籤:android style blog http color os 使用 ar for
在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安全執行緒問題