序言
在Android中Handler无处不在,我们的应用程序的所有生命周期方法都是通过Handler实现线程切换的。而为了保证UI的流畅性防止发生ANR,我们经常需要开启一个线程处理耗时操作,然后通过Handler讲结果显示在UI线程。通过Android的源码可以知道,Android中的触摸事件,按键都是通过主线程处理的,如果把主线程阻塞了,那么手机就不能响应任何操作了。
下面是一个应用程序的启动入口
上面三处就是Looper的创建,和启动循环。
可能有人奇怪,为什么一定要这么麻烦的切换线程,为什么修改UI只能在主线程。因为我们的View是线程不安全的,比如TextView的setText();
以上是setText的源码,可见并没有什么 synchronized 关键字,可知其是线程不安全的,如果两个线程同时去修改就会造成界面混乱。所以,Android中只允许UI线程去改。
而Handler就是Android提供给我们的异步消息框架,用来实现线程切换处理。在其中关键的就是这几个类。
我在这里把源码都贴上,大家有时间自己运行一下试一试。
源码
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() {
// 获取当前线程的Looper
Looper looper = mLooper.get();
if (looper == null) {
throw new RuntimeException("must call looper.perpared()");
}
while (true) {
// 从当前线程的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(测试类,相当于一个Android程序)
package P4;
public class App {
Handler handler;
public static void main(String[] args) {
Looper.prepare(true);
new BackgroundThread(new Handler(), "后台进程").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() + ":后台处理进度" + 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-进度" + finaI);
}
});
}
uiHandler.postMessage(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":下载完成");
}
});
}
}