Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android多線程

android多線程

編輯:關於Android編程

語法和java多線程類似,用法基本相同
一。基本用法:
方法一

class t extends Thread{
@override 
public void run(){}
}
new t().start

方法二

class t implements Runnable{
@override
public void run(){}}

new Thread(new t).start();

或者

new Thread(new Runnable(){
@override
public void run(){}}).start();

在Android當中,通常將線程分為兩種,一種叫做Main Thread,除了Main Thread之外的線程都可稱為Worker Thread。

當一個應用程序運行的時候,Android操作系統就會給該應用程序啟動一個線程,這個線程就是我們的Main Thread,這個線程非常的重要,它主要用來加載我們的UI界面,完成系統和我們用戶之間的交互,並將交互後的結果又展示給我們用戶,所以Main Thread又被稱為UI Thread。

Android系統默認不會給我們的應用程序組件創建一個額外的線程,所有的這些組件默認都是在同一個線程中運行。然而,某些時候當我們的應用程序需要完成一個耗時的操作的時候,例如訪問網絡或者是對數據庫進行查詢時,此時我們的UI Thread就會被阻塞。例如,當我們點擊一個Button,然後希望其從網絡中獲取一些數據,如果此操作在UI Thread當中完成的話,當我們點擊Button的時候,UI線程就會處於阻塞的狀態,此時,我們的系統不會調度任何其它的事件,更糟糕的是,當我們的整個現場如果阻塞時間超過5秒鐘(官方是這樣說的),這個時候就會出現 ANR (Application Not Responding)的現象,此時,應用程序會彈出一個框,讓用戶選擇是否退出該程序。對於Android開發來說,出現ANR的現象是絕對不能被允許的。

另外,由於我們的Android UI控件是線程不安全的,所以我們不能在UI Thread之外的線程當中對我們的UI控件進行操作。因此在Android的多線程編程當中,我們有兩條非常重要的原則必須要遵守:

絕對不能在UI Thread當中進行耗時的操作,不能阻塞我們的UI Thread
不能在UI Thread之外的線程當中操縱我們的UI元素

android 異步處理機制;
AsyncTask:
AsyncTask:異步任務,從字面上來說,就是在我們的UI主線程運行的時候,異步的完成一些操作。AsyncTask允許我們的執行一個異步的任務在後台。我們可以將耗時的操作放在異步任務當中來執行,並隨時將任務執行的結果返回給我們的UI線程來更新我們的UI控件。通過AsyncTask我們可以輕松的解決多線程之間的通信問題。

怎麼來理解AsyncTask呢?通俗一點來說,AsyncTask就相當於Android給我們提供了一個多線程編程的一個框架,其介於Thread和Handler之間,我們如果要定義一個AsyncTask,就需要定義一個類來繼承AsyncTask這個抽象類,並實現其唯一的一個 doInBackgroud 抽象方法。要掌握AsyncTask,我們就必須要一個概念,總結起來就是: 3個泛型,4個步驟。

3個泛型指的是什麼呢?我們來看看AsyncTask這個抽象類的定義,當我們定義一個類來繼承AsyncTask這個類的時候,我們需要為其指定3個泛型參數:

AsyncTask 

((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){ 

    @Override 
    public void onClick(View view) { 
        data = null; 
        data = new ArrayList(); 

        adapter = null; 

        //顯示ProgressDialog放到AsyncTask.onPreExecute()裡 
        //showDialog(PROGRESS_DIALOG); 
        new ProgressTask().execute(data); 
    } 
}); 

private class ProgressTask extends AsyncTask, Void, Integer> { 

/* 該方法將在執行實際的後台操作前被UI thread調用。可以在該方法中做一些准備工作,如在界面上顯示一個進度條。*/ 
@Override 
protected void onPreExecute() { 
    // 先顯示ProgressDialog
    showDialog(PROGRESS_DIALOG); 
} 

/* 執行那些很耗時的後台計算工作。可以調用publishProgress方法來更新實時的任務進度。 */ 
@Override 
protected Integer doInBackground(ArrayList... datas) { 
    ArrayList data = datas[0]; 
    for (int i=0; i<8; i++) { 
        data.add("ListItem"); 
    } 
    return STATE_FINISH; 
} 

/* 在doInBackground 執行完成後,onPostExecute 方法將被UI thread調用, 
 * 後台的計算結果將通過該方法傳遞到UI thread. 
 */ 
@Override 
protected void onPostExecute(Integer result) { 
    int state = result.intValue(); 
    switch(state){ 
    case STATE_FINISH: 
        dismissDialog(PROGRESS_DIALOG); 
        Toast.makeText(getApplicationContext(), 
                "加載完成!", 
                Toast.LENGTH_LONG) 
             .show(); 

        adapter = new ArrayAdapter(getApplicationContext(), 
                android.R.layout.simple_list_item_1, 
                data ); 

        setListAdapter(adapter); 

        break; 

    case STATE_ERROR: 
       dismissDialog(PROGRESS_DIALOG); 
       Toast.makeText(getApplicationContext(), 
               "處理過程發生錯誤!", 
               Toast.LENGTH_LONG) 
            .show();

       adapter = new ArrayAdapter(getApplicationContext(), 
               android.R.layout.simple_list_item_1, 
               data );

          setListAdapter(adapter);

          break;

   default:

   } 
}

Handler:
  線程在代碼是使用標准的java Thread對象來建立,那麼在Android系統中提供了一系列方便的類來管理線程——Looper用來在一個線程中執行消息循環,Handler用來處理消息,HandlerThread創建帶有消息循環的線程。具體可以看下面的詳細介紹。

  當一個程序第一次啟動時,Android會同時啟動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。

  在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。

  2.1 子線程更新UI Android的UI是單線程(Single-threaded)的。

  為了避免拖住GUI,一些較費時的對象應該交給獨立的線程去執行。如果幕後的線程來執行UI對象,Android就會發出錯誤訊息 CalledFromWrongThreadException。以後遇到這樣的異常拋出時就要知道怎麼回事了!

  2.2 Message Queue

  在單線程模型下,為了解決類似的問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue並結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:

  2.2.1. Message 消息

  理解為線程間交流的信息,處理數據後台線程需要更新UI,則發送Message內含一些數據給UI線程。

  2.2.2. Handler 處理者

  是Message的主要處理者,負責Message的發送,Message內容的執行處理。後台線程就是通過傳進來的Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message) 方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。

  2.2.3. Message Queue 消息隊列

  用來存放通過Handler發布的消息,按照先進先出執行。 每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。

  2.2.4. Looper Looper是每條線程裡的Message Queue的管家。

  Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程裡並沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper()得到當前線程的Looper就有可能為NULL。

  對於子線程使用Looper,API Doc提供了正確的使用方法:

package com.test;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

class LooperThread extends Thread { 
    public Handler mHandler; 

    public void run() { 
        Looper.prepare(); //創建本線程的Looper並創建一個MessageQueue
        mHandler = new Handler() { 
            public void handleMessage(Message msg) { 

            // process incoming messages here 
            } 
        }; 

        Looper.loop(); //開始運行Looper,監聽Message Queue 
    }     
} 

  這個Message機制的大概流程:

  1. 在Looper.loop()方法運行開始後,循環地按照接收順序取出Message Queue裡面的非NULL的Message。

  2. 一開始Message Queue裡面的Message都是NULL的。當Handler.sendMessage(Message)到Message Queue,該函數裡面設置了那個Message對象的target屬性是當前的Handler對象。隨後Looper取出了那個Message,則調用該Message的target指向的Hander的dispatchMessage函數對Message進行處理。

  在dispatchMessage方法裡,如何處理Message則由用戶指定,三個判斷,優先級從高到低:

  1) Message裡面的Callback,一個實現了Runnable接口的對象,其中run函數做處理工作;

  2) Handler裡面的mCallback指向的一個實現了Callback接口的對象,由其handleMessage進行處理;

  3) 處理消息Handler對象對應的類繼承並實現了其中handleMessage函數,通過這個實現的handleMessage函數處理消息。

  由此可見,我們實現的handleMessage方法是優先級最低的!

  3. Handler處理完該Message (update UI) 後,Looper則設置該Message為NULL,以便回收!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved