关于看源码
其实我还是很喜欢看别人的想法来对照自己的,但是看不看并不重要我觉得。别人的代码完全淹没掉自己的想法,然后失去自己的想法,遇到问题只能去找别人的方法解决,失去了自己。
当然,别人解决问题的方法,我们当然有必要看,但是完全没必要一字一句去研究,因为他的代码中想必只有20%的地方是思想,80%只是为了解决各种小问题。
尤其是今天看到一个关于handler如何使用不发生内存泄漏的文章,感受颇深。https://blog.csdn.net/alcoholdi/article/details/54948058
入口1 ----Handler handler = new Handler()
打开盒子
①使用了两个参数的构造函数
public Handler() {
this(null, false);
}
转到两个参数的构造函数处
①得到轮询器looper
②得到队列queue
③其余暂时略过
public Handler(Callback callback, boolean async) {
//省略
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
//省略
}
进入Looper.myLooper()
①发现一个新的类SThreadLocal.get()得到轮询器looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
进入sThreadLocal.get()
①Thread t = Thread.currentThread();看看哪个线程创建的handler。
②ThreadLocalMap map = getMap(t);有一个map存的是looper。
③map.getEntry(this);这里的this是ThreadLoca类,根据threadLocal得到looper,然后返回。
④我们明白了:哪个线程创建的handler,它所使用的looper就是哪个线程的。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
T result = (T)e.value;
return result;
}
}
//省略
}
出口
①每一个线程对应了一个轮询器。
②哪个线程创建的handler,handler就持有的是哪个线程的looper。
③每个looper里面自带一个队列。
入口2 ----handler.sendEmptyMessage(0);
打开盒子
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
//略
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
//略
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
//略
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//略
return queue.enqueueMessage(msg, uptimeMillis);
}
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} 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.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
return true;
}
关闭盒子
①经历了很多步骤终于要加入队列了。
②一套操作终于把msg接上去了,看到next,是不是有点熟悉。
入口3----疑问
①事件怎么可以无限执行的。
②消息是怎么被无限取出来的。
③怎么在没有消息的时候阻塞的。
looper中的loop函数中出现了for(;;)
①发现这个函数调用了queue.next();
②出现了分发消息的事件。
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
//略
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
try {
msg.target.dispatchMessage(msg);
} finally {
}
}
//略
}
①原来message的target是handler;
public final class Message implements Parcelable {
/*package*/ Handler target;
}
①熟悉的handlerMessage这个正是我们复写的函数。
public void dispatchMessage(Message msg) {
//略
handleMessage(msg);
}
于是来到了MessageQueue的queue.next();
①抛弃别的东西,我们看到它返回一个msg,msg中间怎么得到的略过。
②我们看到它有一个native方法。
Message next() {
for (;;) {
//略
nativePollOnce(ptr, nextPollTimeoutMillis);
//略
synchronized (this) {
Message msg = mMessages;
//略
return msg;
}
//略
}
}
来到出口处思考一下
答案①:looper里面的轮询一直在向queue索要消息,拿到消息就执行。执行完了继续索要消息。
????没拿到消息就结束,但是我们不能让它结束,还要靠他执行消息呢。
答案②:为了能够不让looper终止,所以queue必须要每次都给looper消息。所以没消息他自己要阻塞等待,阻塞必然就在他里面。
答案③:阻塞必然是在它里面,那么我们来看看这个可疑的方法,百度一下nativePollOnce。
看到这里就放心了,就是它实现了阻塞。不过我们暂时还是不去想它了,暂且记住它(๑╹◡╹)ノ"""。
总结
①每一个线程对应了一个轮询器。
②哪个线程创建的handler,handler就持有的是哪个线程的looper。
③每个looper里面自带一个队列。
④looper执行完就朝queue要消息,queue自己有了消息以后,马上return给looper,looper执行完了,继续要,不断循环。
⑤一个奇妙的native阻塞,实现了等待队列中有消息的效果,同时又不阻塞当前线程。
⑥以上所有内容仅是个人理解,不一定准确。