Skip to content

Commit ac0094a

Browse files
committed
2 parents 9b60050 + 73d2eb2 commit ac0094a

File tree

5 files changed

+212
-6
lines changed

5 files changed

+212
-6
lines changed

Part1/Android/Android内存泄漏总结.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式
2424
举个例子:
2525

2626
```
27-
public class Sample() {
27+
public class Sample {
2828
int s1 = 0;
2929
Sample mSample1 = new Sample();
3030

Part1/Android/Android基础知识.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
onRestart()—>**onStart()**—>onResume(),再次回到运行状态。
5252
* Activity退居后台,且系统内存不足,
5353
系统会杀死这个后台状态的Activity(此时这个Activity引用仍然处在任务栈中,只是这个时候引用指向的对象已经为null),若再次回到这个Activity,则会走onCreate()–>onStart()—>onResume()(将重新走一次Activity的初始化生命周期)
54-
* 锁定屏与解锁屏幕
55-
**只会调用onPause(),而不会调用onStop()方法,开屏后则调用onResume()**
54+
* 锁屏:`onPause()->onStop()`
55+
* 解锁:`onStart()->onResume()`
5656
5757
* 更多流程分支,请参照以下生命周期流程图
5858
![](http://img.blog.csdn.net/20130828141902812)

Part1/Android/Listview详解.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#ListView详解
22
---
3-
直接继承自AbsListView,AbsListView继承自AdapterView,AdapterView继承自AdapterView,AdapterView又继承自ViewGroup。
3+
直接继承自AbsListView,AbsListView继承自AdapterView,AdapterView又继承自ViewGroup。
44

55
Adpater在ListView和数据源之间起到了一个桥梁的作用
66

@@ -15,4 +15,4 @@ RecycleBin机制是ListView能够实现成百上千条数据都不会OOM最重
1515
* getScrapView 用于从废弃缓存中取出一个View,这些废弃缓存中的View是没有顺序可言的,因此getScrapView()方法中的算法也非常简单,就是直接从mCurrentScrap当中获取尾部的一个scrap view进行返回。
1616
* 我们都知道Adapter当中可以重写一个getViewTypeCount()来表示ListView中有几种类型的数据项,而setViewTypeCount()方法的作用就是为每种类型的数据项都单独启用一个RecycleBin缓存机制。
1717

18-
View的流程分三步,onMeasure()用于测量View的大小,onLayout()用于确定View的布局,onDraw()用于将View绘制到界面上。
18+
View的流程分三步,onMeasure()用于测量View的大小,onLayout()用于确定View的布局,onDraw()用于将View绘制到界面上。
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
> 老司机们都知道,Android的线程间通信就靠Handler、Looper、Message、MessageQueue这四个麻瓜兄弟了,那么,他们是怎么运作的呢?下面做一个基于主要源代码的大学生水平的分析。 [原文链接](http://anangryant.leanote.com/post/Handler%E3%80%81Looper%E3%80%81Message%E3%80%81MessageQueue%E5%88%86%E6%9E%90)
2+
3+
##Looper(先分析这个是因为能够引出四者的关系)
4+
在Looper中,维持一个`Thread`对象以及`MessageQueue`,通过Looper的构造函数我们可以知道:
5+
```
6+
private Looper(boolean quitAllowed) {
7+
mQueue = new MessageQueue(quitAllowed);//传入的参数代表这个Queue是否能够被退出
8+
mThread = Thread.currentThread();
9+
}
10+
```
11+
`Looper`在构造函数里干了两件事情:
12+
1. 将线程对象指向了创建`Looper`的线程
13+
2. 创建了一个新的`MessageQueue`
14+
15+
分析完构造函数之后,接下来我们主要分析两个方法:
16+
1. `looper.loop()`
17+
2. `looper.prepare()`
18+
19+
###looper.loop()(在当前线程启动一个Message loop机制,此段代码将直接分析出Looper、Handler、Message、MessageQueue的关系)
20+
```
21+
public static void loop() {
22+
final Looper me = myLooper();//获得当前线程绑定的Looper
23+
if (me == null) {
24+
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
25+
}
26+
final MessageQueue queue = me.mQueue;//获得与Looper绑定的MessageQueue
27+
28+
// Make sure the identity of this thread is that of the local process,
29+
// and keep track of what that identity token actually is.
30+
Binder.clearCallingIdentity();
31+
final long ident = Binder.clearCallingIdentity();
32+
33+
//进入死循环,不断地去取对象,分发对象到Handler中消费
34+
for (;;) {
35+
Message msg = queue.next(); // 不断的取下一个Message对象,在这里可能会造成堵塞。
36+
if (msg == null) {
37+
// No message indicates that the message queue is quitting.
38+
return;
39+
}
40+
41+
// This must be in a local variable, in case a UI event sets the logger
42+
Printer logging = me.mLogging;
43+
if (logging != null) {
44+
logging.println(">>>>> Dispatching to " + msg.target + " " +
45+
msg.callback + ": " + msg.what);
46+
}
47+
48+
//在这里,开始分发Message了
49+
//至于这个target是神马?什么时候被赋值的?
50+
//我们一会分析Handler的时候就会讲到
51+
msg.target.dispatchMessage(msg);
52+
53+
if (logging != null) {
54+
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
55+
}
56+
57+
// Make sure that during the course of dispatching the
58+
// identity of the thread wasn't corrupted.
59+
final long newIdent = Binder.clearCallingIdentity();
60+
if (ident != newIdent) {
61+
Log.wtf(TAG, "Thread identity changed from 0x"
62+
+ Long.toHexString(ident) + " to 0x"
63+
+ Long.toHexString(newIdent) + " while dispatching to "
64+
+ msg.target.getClass().getName() + " "
65+
+ msg.callback + " what=" + msg.what);
66+
}
67+
68+
//当分发完Message之后,当然要标记将该Message标记为 *正在使用* 啦
69+
msg.recycleUnchecked();
70+
}
71+
}
72+
```
73+
*分析了上面的源代码,我们可以意识到,最重要的方法是:*
74+
1. `queue.next()`
75+
2. `msg.target.dispatchMessage(msg)`
76+
3. `msg.recycleUnchecked()`
77+
78+
其实Looper中最重要的部分都是由`Message``MessageQueue`组成的有木有!这段最重要的代码中涉及到了四个对象,他们与彼此的关系如下:
79+
1. `MessageQueue`:装食物的容器
80+
2. `Message`:被装的食物
81+
3. `Handler`(msg.target实际上就是`Handler`):食物的消费者
82+
4. `Looper`:负责分发食物的人
83+
84+
85+
###looper.prepare()(在当前线程关联一个Looper对象)
86+
```
87+
private static void prepare(boolean quitAllowed) {
88+
if (sThreadLocal.get() != null) {
89+
throw new RuntimeException("Only one Looper may be created per thread");
90+
}
91+
//在当前线程绑定一个Looper
92+
sThreadLocal.set(new Looper(quitAllowed));
93+
}
94+
```
95+
以上代码只做了两件事情:
96+
1. 判断当前线程有木有`Looper`,如果有则抛出异常(在这里我们就可以知道,Android规定一个线程只能够拥有一个与自己关联的`Looper`)。
97+
2. 如果没有的话,那么就设置一个新的`Looper`到当前线程。
98+
99+
--------------
100+
##Handler
101+
由于我们使用Handler的通常性的第一步是:
102+
```
103+
Handler handler = new Handler(){
104+
//你们有没有很好奇这个方法是在哪里被回调的?
105+
//我也是!所以接下来会分析到哟!
106+
@Override
107+
public void handleMessage(Message msg) {
108+
//Handler your Message
109+
}
110+
};
111+
```
112+
所以我们先来分析`Handler`的构造方法
113+
```
114+
//空参数的构造方法与之对应,这里只给出主要的代码,具体大家可以到源码中查看
115+
public Handler(Callback callback, boolean async) {
116+
//打印内存泄露提醒log
117+
....
118+
119+
//获取与创建Handler线程绑定的Looper
120+
mLooper = Looper.myLooper();
121+
if (mLooper == null) {
122+
throw new RuntimeException(
123+
"Can't create handler inside thread that has not called Looper.prepare()");
124+
}
125+
//获取与Looper绑定的MessageQueue
126+
//因为一个Looper就只有一个MessageQueue,也就是与当前线程绑定的MessageQueue
127+
mQueue = mLooper.mQueue;
128+
mCallback = callback;
129+
mAsynchronous = async;
130+
131+
}
132+
```
133+
*带上问题:*
134+
1. `Looper.loop()`死循环中的`msg.target`是什么时候被赋值的?
135+
2. `handler.handleMessage(msg)`在什么时候被回调的?
136+
137+
###A1:`Looper.loop()`死循环中的`msg.target`是什么时候被赋值的?
138+
要分析这个问题,很自然的我们想到从发送消息开始,无论是`handler.sendMessage(msg)`还是`handler.sendEmptyMessage(what)`,我们最终都可以追溯到以下方法
139+
```
140+
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
141+
//引用Handler中的MessageQueue
142+
//这个MessageQueue就是创建Looper时被创建的MessageQueue
143+
MessageQueue queue = mQueue;
144+
145+
if (queue == null) {
146+
RuntimeException e = new RuntimeException(
147+
this + " sendMessageAtTime() called with no mQueue");
148+
Log.w("Looper", e.getMessage(), e);
149+
return false;
150+
}
151+
//将新来的Message加入到MessageQueue中
152+
return enqueueMessage(queue, msg, uptimeMillis);
153+
}
154+
```
155+
156+
我们接下来分析`enqueueMessage(queue, msg, uptimeMillis)`:
157+
```
158+
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
159+
//显而易见,大写加粗的赋值啊!
160+
**msg.target = this;**
161+
if (mAsynchronous) {
162+
msg.setAsynchronous(true);
163+
}
164+
return queue.enqueueMessage(msg, uptimeMillis);
165+
}
166+
```
167+
168+
169+
###A2:`handler.handleMessage(msg)`在什么时候被回调的?
170+
通过以上的分析,我们很明确的知道`Message`中的`target`是在什么时候被赋值的了,我们先来分析在`Looper.loop()`中出现过的过的`dispatchMessage(msg)`方法
171+
172+
```
173+
public void dispatchMessage(Message msg) {
174+
if (msg.callback != null) {
175+
handleCallback(msg);
176+
} else {
177+
if (mCallback != null) {
178+
if (mCallback.handleMessage(msg)) {
179+
return;
180+
}
181+
}
182+
//看到这个大写加粗的方法调用没!
183+
**handleMessage(msg);**
184+
}
185+
}
186+
```
187+
188+
加上以上分析,我们将之前分析结果串起来,就可以知道了某些东西:
189+
`Looper.loop()`不断地获取`MessageQueue`中的`Message`,然后调用与`Message`绑定的`Handler`对象的`dispatchMessage`方法,最后,我们看到了`handleMessage`就在`dispatchMessage`方法里被调用的。
190+
191+
------------------
192+
通过以上的分析,我们可以很清晰的知道Handler、Looper、Message、MessageQueue这四者的关系以及如何合作的了。
193+
194+
#总结:
195+
当我们调用`handler.sendMessage(msg)`方法发送一个`Message`时,实际上这个`Message`是发送到**与当前线程绑定**的一个`MessageQueue`中,然后**与当前线程绑定**`Looper`将会不断的从`MessageQueue`中取出新的`Message`,调用`msg.target.dispathMessage(msg)`方法将消息分发到与`Message`绑定的`handler.handleMessage()`方法中。
196+
197+
一个`Thread`对应多个`Handler`
198+
一个`Thread`对应一个`Looper``MessageQueue``Handler``Thread`共享`Looper``MessageQueue`
199+
`Message`只是消息的载体,将会被发送到**与线程绑定的唯一的**`MessageQueue`中,并且被**与线程绑定的唯一的**`Looper`分发,被与其自身绑定的`Handler`消费。
200+
201+
------
202+
- Enjoy Android :) 如果有误,轻喷,欢迎指正。
203+
204+
205+

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
* [Android基础知识](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android基础知识.md)
99
* [Android内存泄漏总结](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android内存泄漏总结.md)
1010
* [Handler内存泄漏分析及解决](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Handler内存泄漏分析及解决.md)
11-
* [Android性能优化](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android性能优化.md)
11+
* [Handler、Looper、Message、MessageQueue基础流程分析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/线程通信基础流程分析.md)
12+
* [Android性能优化](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android性能优化.md)
1213
* [ListView详解](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Listview详解.md)
1314
* [RecyclerView和ListView的异同](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Recyclerview和Listview的异同.md)
1415
* [AsyncTask源码分析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Asynctask源码分析.md)

0 commit comments

Comments
 (0)