序言
在Android中Handler無處不在催首,我們的應(yīng)用程序的所有生命周期方法都是通過Handler實現(xiàn)線程切換的。而為了保證UI的流暢性防止發(fā)生ANR,我們經(jīng)常需要開啟一個線程處理耗時操作,然后通過Handler講結(jié)果顯示在UI線程。通過Android的源碼可以知道山橄,Android中的觸摸事件,按鍵都是通過主線程處理的,如果把主線程阻塞了航棱,那么手機(jī)就不能響應(yīng)任何操作了睡雇。
下面是一個應(yīng)用程序的啟動入口
上面三處就是Looper的創(chuàng)建,和啟動循環(huán)饮醇。
可能有人奇怪它抱,為什么一定要這么麻煩的切換線程,為什么修改UI只能在主線程朴艰。因為我們的View是線程不安全的观蓄,比如TextView的setText();
以上是setText的源碼,可見并沒有什么 synchronized 關(guān)鍵字祠墅,可知其是線程不安全的侮穿,如果兩個線程同時去修改就會造成界面混亂。所以毁嗦,Android中只允許UI線程去改亲茅。
而Handler就是Android提供給我們的異步消息框架,用來實現(xiàn)線程切換處理狗准。在其中關(guān)鍵的就是這幾個類克锣。
我在這里把源碼都貼上,大家有時間自己運(yùn)行一下試一試腔长。
源碼
Handler
package P4;
public class Handler {
Looper looper;
public Handler(Looper looper) {
this.looper = looper;
}
public Handler() {
this(Looper.mainLooper());
}
public void handleMessage(Message message) {
if (message.callback != null) {
message.callback.run();
}
};
public void sendMessage(Message message) {
looper.getQueue().add(message);
}
public void sendMessageEmpty(int what) {
Message message = new Message();
message.what = what;
looper.getQueue().add(message);
}
public void postMessage(Runnable callback) {
Message message = new Message();
message.callback = callback;
looper.getQueue().add(message);
}
}
Looper
package P4;
public class Looper {
private static ThreadLocal<Looper> mLooper = new ThreadLocal<>();
private static Looper mainLooper;
private MessageQueue queue = new MessageQueue();
public static void prepare(boolean isMain) {
if (mLooper.get() != null) {
throw new RuntimeException("looper has prepared");
}
mLooper.set(new Looper());
if (isMain) {
mainLooper = mLooper.get();
}
}
/**
* 獲取主線程的Looper
*
* @return
*/
public static Looper mainLooper() {
return mainLooper;
}
public static void loop() {
// 獲取當(dāng)前線程的Looper
Looper looper = mLooper.get();
if (looper == null) {
throw new RuntimeException("must call looper.perpared()");
}
while (true) {
// 從當(dāng)前線程的MessageQueue中獲取需要處理的消息
// 如果消息為空的話就等待
Message message = looper.queue.next();
if (message.target != null) {
message.target.handleMessage(message);
} else if (message.callback != null) {
message.callback.run();
}
}
}
public MessageQueue getQueue() {
return queue;
}
}
Message
package P4;
public class Message {
public Runnable callback;
public int what;
public int arg1;
public int arg2;
public Handler target;
}
MessageQueue
package P4;
import java.util.ArrayList;
import java.util.List;
public class MessageQueue {
List<Message> messages = new ArrayList<>();
public synchronized Message next() {
while (messages.size() == 0) {
try {
//消息為空袭祟,等待
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
notifyAll();
return messages.remove(0);
}
public synchronized void add(Message message) {
messages.add(message);
//喚醒
notifyAll();
}
}
APP(測試類,相當(dāng)于一個Android程序)
package P4;
public class App {
Handler handler;
public static void main(String[] args) {
Looper.prepare(true);
new BackgroundThread(new Handler(), "后臺進(jìn)程").start();
Looper.loop();
}
}
class BackgroundThread extends Thread {
Handler uiHandler;
public BackgroundThread(Handler handler, String name) {
uiHandler = handler;
setName(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":后臺處理進(jìn)度" + i);
try {
sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final int finaI = i;
uiHandler.postMessage(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":前臺更新UI-進(jìn)度" + finaI);
}
});
}
uiHandler.postMessage(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":下載完成");
}
});
}
}