handler主要是用来处理进程内通信的
首先我们先写一个handler
public class Handler {
public void handleMessage( Message msg) {
}
public void sendMessage(Message msg){
msg.setHandler(this);
Looper.mq.enqueueMessage(msg);
}
}
这两个是主要方法,一个发,一个收
public class Message {
String msg ;
Handler target ;
Message next ;
public Message(String msg){
this.msg = msg ;
}
public void setHandler(Handler handler){
this.target = handler ;
}
public Handler getHandler(){
return this.target ;
}
@Override
public String toString() {
return "Message{" +
"msg='" + msg + '\'' +
'}';
}
}
这是重写的简单的message
之后加入我们要发送和接收数据,当然如果我们只发送一个数据,我们就可直接使用handler的方法,当我们有大量数据时呢,如果都使用send,势必会导致线程阻塞,所以我们就想着添加一个队列,我们先把要发送的数据添加进去,之后他们想要处理的数据在慢慢处理,于是我们就写了
public class MessageQueue {
Message mMessage =null;
public void enqueueMessage(Message msg){
Message p = mMessage;
if (p == null ) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessage = msg;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null) {
break;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
Log.d("xsr", "enqueueMessage: "+msg.toString());
Log.d("xsr", "enqueueMessage: "+mMessage.toString());
}
public Message next(){
synchronized (this) {
// Log.d("xsr", "next: "+mMessage.toString());
if (mMessage == null) {
return null ;
}
Message msg = mMessage; // 获取队列头的消息
mMessage = msg.next; // 将队列头移动到下一个消息
msg.next = null; // 断开与下一个消息的链接
return msg; // 返回当前头消息
}
}
}
消息添加到队列了,我们需要执行队列里方法的类,于是就有了looper
这里就需要思考一个问题了,looper可以有多个吗,我们看个方法就明白了
public static void loop(){
for(;;){
final Looper me = sThreadLocal.get();
Message msg = me.mq.next();
if(msg==null){
break ;
}
msg.target.handleMessage(msg);
}
}
这是我简写的一个方法,他有个for循环会一直判断,如果有多个looper,前面的循环没执行完,后面就会一直阻塞,不就有发生之前的问题了吗,那queue将没有意义,所以我们要保证只有一个looper,那我们怎么做呢 我们想到threadLocal ,我们看下这个方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
他的key是当前线程, values我们可以存放一个looper,这样我们就可以得到这个唯一的looper了
我们看下方法实现
public class Looper {
public static MessageQueue mq = new MessageQueue() ;
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare(){
if(sThreadLocal.get()!=null){
}
sThreadLocal.set(new Looper());
}
public static void loop(){
for(;;){
final Looper me = sThreadLocal.get();
Message msg = me.mq.next();
if(msg==null){
break ;
}
msg.target.handleMessage(msg);
}
}
}
我们在prepare中确保了只有一个looper存在,然后使用loop执行
最后我们看下最终的调用
public class MainActivity extends Activity {
Handler mhand = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("xsr", "onCreate: activity_main ");
Looper.prepare();
new Thread(new Runnable() {
@Override
public void run() {
Log.d("xsr", "thread ");
mhand = new Handler(){
@Override
public void handleMessage( Message msg) {
Log.d("xsr", "handleMessage: "+msg.toString());
}
};
}
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Log.d("xsr", "onCreate: send");
mhand.sendMessage(new Message("xsr111"));
mhand.sendMessage(new Message("xsr22"));
mhand.sendMessage(new Message("xsr3"));
Looper.loop();
}
}
这样我们就实现了简易的handler通信
注意这里会存在内存泄露是因为长生命周期持有了短生命周期
threadlocal->queue->message->handler->activity
要解决内存泄漏简单方法是使用static静态方法来解决