線程
由于Android的Activity中默認所有代碼都在主線程(UI線程)中執行,如果在這里面執行耗時任務(例如下載),界面就會無反應且不可操作,直到耗時任務執行完畢。
如果想在執行耗時任務的同時又想讓界面不會沒有反應,就需要新開一個線程(Thread)。系統會在UI線程和新開的線程之間不斷切換,由于切換速度極快且可以操作界面,就會給人一種沒有在執行耗時任務的感覺。
JAVA中的線程
在JAVA中,有兩個跟線程關系最緊密的類或接口:
- Runnable接口:只有一個抽象方法run()。這是線程實際執行的方法,應該實現這個方法并把要在線程中執行的代碼放到這里。
Tread類:實現了Runnable接口。通過執行start()來開啟線程,并在新的線程中執行run()的代碼。
能否直接執行Tread的run()方法呢?答案是不行。如果直接在Thead執行run(),它仍然會在當前線程(例如UI線程)里執行run()的代碼,而不是在新的線程中運行。
以下是線程的一種寫法:
new Thread(new Runnable() {
@Override
public void run() {
// 在線程中運行的代碼
}
}).start();
Android中的線程
任務(task):執行一個特定操作的一個Runnable對象或者Runnable對象集。
在Android中,可以使用上面介紹的方法開啟線程。不過那樣的寫法會使得一旦線程的任務結束,不會再次運行這個線程(也就是一次性線程)。
當你想為不同數據集而重復執行某個任務時,可以使用IntentService。不過要注意,同一段時間只處理一個數據集。
如果上面兩者都不符合你的要求,那么可以試試 ThreadPoolExecutor ,它可以實現以下功能:
- 當資源準備好時自動執行任務
- 多個任務同時執行
當 ThreadPoolExecutor 的線程池中有一個線程為空閑時, ThreadPoolExecutor 會從一個隊列(queue)中取出一個任務來執行。
線程間數據交換
因為新開的線程和處理界面的線程是分開的,于是在Android中使用線程會遇到一個問題:線程處理完的數據如何更新到界面上?
JAVA
你可以實現 BlockingQueue 接口。將其實例傳入線程中,在線程里面使用put(Object)將數據放入隊列,使用take()從隊列中取出數據。
以下是官方的例子:
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
Android
Android添加了幾個類,用來處理數據交換。
- Handler : 線程之間交換數據的通道,用于接收和發送消息。如果在UI線程里創建Handler,則該Handler里的handleMessage(Message)方法會在UI線程里執行。
- Message : 線程A發送消息給線程B時,需要將消息封裝到Message里面。通過在線程A內部執行線程B的Handler.sendMessage(Message)將Message傳給線程B,此時會執行Handler的handleMessage(Message)方法。
- MessageQueue : 當發送多個Message時,為了不造成混亂,將這些Message組成一個隊列,逐個處理。每個線程中只能有一個MessageQueue。這個隊列由Looper管理。
- Looper : 管理MessageQueue。每次從隊列里面取出一個Message,交給Handler處理。Handler處理完畢后再去隊列中取出Message。
這些類太多了,有時候寫起來麻煩。為了簡化線程的寫法,Android將上面那些封裝起來,于是就有了AsyncTask。
Android對線程類的封裝
AsyncTask有四個重要的方法:
- onPreExecute() :(UI線程)后臺任務執行前在UI線程上做某些初始化操作
- doInBackground(Params ...) :(子線程)相當于Runnable的run()方法。可以在這個方法內計算進度,并調用publishProgress(Progress ...)傳遞給onProgressUpdate(Progress ...)方法
- onProgressUpdate(Progress ...) : (UI線程)用于更新界面上的進度信息
- onPostExecute(Result) :(UI線程)用于子線程處理完畢后對結果進行處理
AsyncTask是一個抽象類,需要創建一個類去繼承它。AsyncTask有三個泛型參數,它們用途依次為:
- 執行任務所需要的參數
- 當前進度的單位
- 任務的結果
執行AsyncTask的execute()方法以開始任務。
文章列表