說到線程,大家都知道,可以當作android進程的一個輕量級的表現,只是不佔有空間和資源。在android中,有一個線程是我們最常接觸到的,當我們做的一個應用,在第一次進入的時候,進入第一個Activity的時候,android自身就會自動創建一個用於控制一些控件以及繪圖的MainUI線程,也就是我們說的activity主線程。
說到這裏,就不得不提到一個概念,它就是消息隊列,由於activity 的主線程裏面已經給我們準備好了消息隊列,所以我們只需要在用的時候直接用就可以了,但在自己創建的子線程裏面卻不行,因爲子線程本身並沒有消息隊列這個東西,在我們做線程交互的時候,刷新主界面的時候,往往是通過Handle來完成的,這裏不得不提到另一個東東,它叫LOOP,當我們從子線程裏面,通過handle來發送一個消息出來之後,LOOP會把這個消息發送回到主線程裏面,然後通過消息隊列的方法,來處理這些消息,最終達成我們刷新主界面的效果。
那如何在我們自己創建的子線程裏面實現消息隊列,很簡單,調用Looper.prepare(),那麼系統就會自動的爲該線程建立一個消息隊列,然後調用 Looper.loop();之後就進入了消息循環,這個之後就可以發消息、取消息、和處理消息。這個方法對於平常,我們自己一些用來控制線程交互的實現,非常有用,所以分享一下。
說到這裏,可能大家時常會遇到一些handle之後,好像沒用的現象,這是因爲,handle之後,LOOP把消息傳到了消息隊列的尾部,這是沒有問題的,但是在處理端的時候,就有可能會出現阻塞的現象,所以,用handle來處理一些複雜的圖象更新的時候,有時候有出現一些不可靠的現象。但Handle本身有自己的優勢,就是使用簡單,易懂,而且對於一般應用來說,出錯的情況並不是很頻繁,所以使用也就特別多。
有可能大家會問,什麼是可靠的呢,這裏就不得不提到另一個東西,叫AsyncTask,簡單來說,就是異步任務。
實現:
1) 子類化AsyncTask
2) 實現AsyncTask中定義的下面一個或幾個方法
onPreExecute() 開始執行前的準備工作;
doInBackground(Params...) 開始執行後臺處理,可以調用publishProgress方法來更新實時的任務進度;
onProgressUpdate(Progress...) 在publishProgress方法被調用後,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
onPostExecute(Result) 執行完成後的操作,傳送結果給UI 線程。
注意: 1) AsyncTask的實例必須在UI thread中創建;
2) AsyncTask.execute方法必須在UI thread中調用;
3)該task只能被執行一次,否則多次調用時將會出現異常。而且是不能手動停止
下面是一個例子,AsyncTask_eoe
- package xiaohang.zhimeng;
- import android.app.Activity;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.os.SystemClock;
- import android.widget.TextView;
- import android.widget.Toast;
- /**
- * 一個使用異步任務的例子。一般來說一個異步任務只執行一次,這個例子有點非主流,任務結束後會觸發下一次任務執行。
- * 由任務task在屏幕上打印數字,第一次任務執行由主Activity的onCreate觸發,每次任務結束後
- * 設定下一次觸發的時間,共執行5次。對於任務來說doInBackground()接收任務的參數params,並執行產生數字的動作,每一個數字
- * 產生後調用一次publishProgress()來更新UI,這個函數本身也是異步的只是用來發個消息調用完成後立即返回,
- * 而產生數字的動作在繼續進行。更新界面的操作在onProgressUpdate()中設定。 所有的on函數都由系統調用,不能用戶調用。
- * 代碼中使用Handler是爲了能觸發任務執行,android規定這種異步任務每次執行完就結束,若要重新執行需要new一個新的。
- * 異步任務只能在UI線程裏面創建和執行
- */
- public class testAsync extends Activity {
- private final int MSG_TIMER = 10000;
- private TextView vText = null;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test);
- vText = (TextView) findViewById(R.id.TextView01);
- vText.setText("Num...");
- new task().execute("->");
- }
- // 接收任務task發來的消息,觸發一個新的任務
- private final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // TODO Auto-generated method stub
- super.handleMessage(msg);
- System.out.println("Handler name -----------> " + Thread.currentThread().getName());
- System.out.println("Handler id ------------> " + Thread.currentThread().getId());
- switch (msg.what) {
- case MSG_TIMER:
- new task().execute("->");
- break;
- }
- }
- };
- // 任務執行次數
- private static int times = 1;
- // AsyncTask<>的參數類型由用戶設定,這裏設爲三個String
- // 第一個String代表輸入到任務的參數類型,也即是doInBackground()的參數類型
- // 第二個String代表處理過程中的參數類型,也就是doInBackground()執行過程中的產出參數類型,通過publishProgress()發消息
- // 傳遞給onProgressUpdate()一般用來更新界面
- // 第三個String代表任務結束的產出類型,也就是doInBackground()的返回值類型,和onPostExecute()的參數類型
- private class task extends AsyncTask<String, String, String> {
- // 後臺執行的耗時任務,接收參數並返回結果
- // 當onPostExecute()執行完,在後臺線程中被系統調用
- @Override
- protected String doInBackground(String... params) {
- System.out.println("doInBackground name -----> " + Thread.currentThread().getName());
- System.out.println("doInBackground id -----> " + Thread.currentThread().getId());
- // TODO Auto-generated method stub
- // 在這裏產生數據,送給onProgressUpdate以更新界面
- String pre = params[0];
- System.out.println("pre is ----->" + pre);
- for (int i = 0; i < 5; i++) {
- System.out.println("note i am begin sleep ");
- publishProgress(pre + i);
- // 這裏是否需要停頓下
- System.out.println("hua li de bu zhuo " + pre + i);
- SystemClock.sleep(1000);
- }
- return "任務結束";
- }
- // 任務執行結束後,在UI線程中被系統調用
- // 一般用來顯示任務已經執行結束
- @Override
- protected void onPostExecute(String result) {
- // TODO Auto-generated method stub
- System.out.println("onPostExecute name --------> " + Thread.currentThread().getName());
- System.out.println("onPostExecute id --------> " + Thread.currentThread().getName());
- super.onPostExecute(result);
- Toast.makeText(testAsync.this, result, Toast.LENGTH_SHORT).show();
- // 任務執行5次後推出
- if (times > 5) {
- return;
- }
- // 設定下一次任務觸發時間
- Message msg = Message.obtain();
- msg.what = MSG_TIMER;
- handler.sendMessageDelayed(msg, 10000L);
- }
- // 最先執行,在UI線程中被系統調用
- // 一般用來在UI中產生一個進度條
- @Override
- protected void onPreExecute() {
- // TODO Auto-generated method stub
- System.out.println("onPreExecute id -------> " + Thread.currentThread().getId());
- System.out.println("onPreExecute name -------> " + Thread.currentThread().getName() );
- super.onPreExecute();
- Toast.makeText(testAsync.this, "開始執行第" + times + "次任務: " + this,
- Toast.LENGTH_SHORT).show();
- times++;
- }
- // 更新界面操作,在收到更新消息後,在UI線程中被系統調用
- @Override
- protected void onProgressUpdate(String... values) {
- // TODO Auto-generated method stub
- System.out.println("onProgressUpdate id ---------> " + Thread.currentThread().getId());
- System.out.println("onProgressUpdate name -------> " + Thread.currentThread().getName());
- super.onProgressUpdate(values);
- vText.append(values[0]);
- }
- }
- }
這個例子,寫得很好,裏面寫了很多關於它的一些使用的方法,注意在使用execute(XXX)裏面的參數,就是對應到下面幾個方法裏面的參數,AsyncTask<Params, Progress, Result>,這個就是相應的映射的參數表。