Skip to content

Commit 808844f

Browse files
committed
update file
1 parent f834ce5 commit 808844f

12 files changed

+88
-85
lines changed

Diff for: SourceAnalysis/Activity界面绘制过程详解.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void setContentView(int layoutResID) {
4141
// decor, when theme attributes and the like are crystalized. Do not check the feature
4242
// before this happens.
4343
if (mContentParent == null) {
44-
// 内部会创建mContentParent, 如果mDecor为null就创建,然后如果mContentParent为null,就根据当前要显示的主题去添加对应的布局,
44+
// 内部会创建mContentParent, 如果mDecor为null就创建,然后如果mContentParent为null,就根据当前要显示的主题去添加对应的布局,
4545
// 并把该布局中id为content的ViewGroup赋值给mContentParent。
4646
installDecor();
4747
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
@@ -54,7 +54,7 @@ public void setContentView(int layoutResID) {
5454
getContext());
5555
transitionTo(newScene);
5656
} else {
57-
// 把布局inflate后添加到mContentParent中
57+
// 把布局inflate后添加到mContentParent中
5858
mLayoutInflater.inflate(layoutResID, mContentParent);
5959
}
6060
final Callback cb = getCallback();
@@ -582,4 +582,4 @@ protected ViewGroup generateLayout(DecorView decor) {
582582
---
583583

584584
- 邮箱 :charon.chui@gmail.com
585-
- Good Luck!
585+
- Good Luck!

Diff for: SourceAnalysis/Android Touch事件分发详解.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ Android Touch事件分发详解
33

44
先说一些基本的知识,方便后面分析源码时能更好理解。
55
- 所有`Touch`事件都被封装成`MotionEvent`对象,包括`Touch`的位置、历史记录、第几个手指等.
6-
- 事件类型分为`ACTION_DOWN`,`ACTION_UP`,`ACTION_MOVE`,`ACTION_POINTER_DOWN`,`ACTION_POINTER_UP`,`ACTION_CANCEL`, 每个
6+
- 事件类型分为`ACTION_DOWN`,`ACTION_UP`,`ACTION_MOVE`,`ACTION_POINTER_DOWN`,`ACTION_POINTER_UP`,`ACTION_CANCEL`,
77
一个完整的事件以`ACTION_DOWN`开始`ACTION_UP`结束,并且`ACTION_CANCEL`只能由代码引起.一般对于`CANCEL`的处理和`UP`的相同。
88
`CANCEL`的一个简单例子:手指在移动的过程中突然移动到了边界外,那么这时`ACTION_UP`事件了,所以这是的`CANCEL``UP`的处理是一致的。
9-
- 事件的处理分别为`dispatchTouchEveent()`分发事件(`TextView`等这种最小的`View`中不会有该方式)、`onInterceptTouchEvent()`拦截事件(`ViewGroup`中拦截事件)、`onTouchEvent()`消费事件.这些方法的返回值如果是true表示事件被当前视图消费掉。
9+
- 事件的处理分别为`dispatchTouchEvent()`分发事件(`TextView`等这种最小的`View`中不会有该方式)、`onInterceptTouchEvent()`拦截事件(`ViewGroup`中拦截事件)、`onTouchEvent()`消费事件.这些方法的返回值如果是true表示事件被当前视图消费掉。
1010
- 事件从`Activity.dispatchTouchEveent()`开始传递,只要没有停止拦截,就会从最上层(`ViewGroup`)开始一直往下传递,子`View`通过`onTouchEvent()`消费事件。(隧道式向下分发).
11-
- 如果时间从上往下一直传递到最底层的子`View`,但是该`View`没有消费该事件(不是clickable或longclickable),那么该事件会反序网上传递(从该`View`传递给自己的`ViewGroup`,然后再传给更上层的`ViewGroup`直至传递给`Activity.onTouchEvent()`).
11+
- 如果时间从上往下一直传递到最底层的子`View`,但是该`View`没有消费该事件(不是clickable或longclickable),那么该事件会反序往上传递(从该`View`传递给自己的`ViewGroup`,然后再传给更上层的`ViewGroup`直至传递给`Activity.onTouchEvent()`).
1212
(冒泡式向上处理).
1313
- 如果`View`没有消费`ACTION_DOWN`事件,之后其他的`MOVE``UP`等事件都不会传递过来.
1414
- 事件由父`View(ViewGroup)`传递给子`View`,`ViewGroup`可以通过`onInterceptTouchEvent()`方法对事件进行拦截,停止其往下传递,如果拦截(返回`true`)后该事件
@@ -51,11 +51,11 @@ public boolean dispatchTouchEvent(MotionEvent ev) {
5151
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
5252
onUserInteraction();
5353
}
54-
// 首先交给本Activity对应的Window来进行分发,如果分发了,就返回true,事件循环结束
54+
// 首先交给本Activity对应的Window来进行分发,如果分发了,就返回true,事件循环结束
5555
if (getWindow().superDispatchTouchEvent(ev)) {
5656
return true;
5757
}
58-
// 如果window返回了false,就意味着所有view的ontouchevent都返回了false,那么只能是Activity来决定消费不消费
58+
// 如果window返回了false,就意味着所有view的ontouchevent都返回了false,那么只能是Activity来决定消费不消费
5959
return onTouchEvent(ev);
6060
}
6161
```
@@ -115,8 +115,8 @@ public boolean superDispatchTouchEvent(MotionEvent event) {
115115
return super.dispatchTouchEvent(event);
116116
}
117117
```
118-
是调用了`super.dispatchTouchEveent()`,而`DecorView`的父类是`FrameLayout`所以我们找到`FrameLayout.dispatchTouchEveent()`.
119-
我们看到`FrameLayout`中没有重写`dispatchTouchEveent()`方法,所以我们再找到`FrameLayout`的父类`ViewGroup`.看`ViewGroup.dispatchTouchEveent()`实现。
118+
是调用了`super.dispatchTouchEvent()`,而`DecorView`的父类是`FrameLayout`所以我们找到`FrameLayout.dispatchTouchEvent()`.
119+
我们看到`FrameLayout`中没有重写`dispatchTouchEvent()`方法,所以我们再找到`FrameLayout`的父类`ViewGroup`.看`ViewGroup.dispatchTouchEvent()`实现。
120120
新大陆浮现了...
121121
```java
122122
/**
@@ -145,21 +145,21 @@ public boolean dispatchTouchEvent(MotionEvent ev) {
145145
// The framework may have dropped the up or cancel event for the previous gesture
146146
// due to an app switch, ANR, or some other state change.
147147
cancelAndClearTouchTargets(ev);
148-
// 重置FLAG_DISALLOW_INTERCEPT
148+
// 重置FLAG_DISALLOW_INTERCEPT
149149
resetTouchState();
150150
// 如果是`Down`,那么`mFirstTouchTarget`到这里肯定是`null`.因为是新一系列手势的开始。
151151
// `mFirstTouchTarget`是处理第一个事件的目标。
152152
}
153153

154-
// 检查是否拦截该事件(如果`onInterceptTouchEvent()`返回true就拦截该事件)
154+
// 检查是否拦截该事件(如果`onInterceptTouchEvent()`返回true就拦截该事件)
155155
// Check for interception.
156156
final boolean intercepted;
157-
// 当事件由ViewGroup的子元素成功处理时,mFirstTouchTarget会被赋值并指向子元素,反之被ViewGroup拦截时,mFirstTouchTarget则为null
157+
// 当事件由ViewGroup的子元素成功处理时,mFirstTouchTarget会被赋值并指向子元素,反之被ViewGroup拦截时,mFirstTouchTarget则为null
158158
if (actionMasked == MotionEvent.ACTION_DOWN
159159
|| mFirstTouchTarget != null) {
160160
// 标记事件不允许被拦截, 默认是`false`, 该值可以通过`requestDisallowInterceptTouchEvent(true)`方法来设置,
161161
// 通知父`View`不要拦截该`View`上的事件。FLG_DISALLOW_INTERCEPT是在View中通过
162-
// reqeustDisallowInterceptTouchEvent来设置
162+
// reqeustDisallowInterceptTouchEvent来设置
163163
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
164164
if (!disallowIntercept) {
165165
// 判断该`ViewGroup`是否要拦截该事件。`onInterceptTouchEvent()`方法默认返回`false`即不拦截。
@@ -370,7 +370,7 @@ private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
370370
// or filtering. The important part is the action, not the contents.
371371
final int oldAction = event.getAction();
372372

373-
// 这就是为什么时间被拦截之后,之前处理过该事件的`View`会收到`CANCEL`.
373+
// 这就是为什么事件被拦截之后,之前处理过该事件的`View`会收到`CANCEL`.
374374
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
375375
event.setAction(MotionEvent.ACTION_CANCEL);
376376
if (child == null) {
@@ -439,7 +439,7 @@ private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
439439
```
440440

441441

442-
上面讲了`ViewGroup``dispatchTouchEveent()`有些地方会调用`super.dispatchTouchEveent()`,而`ViewGroup`的父类就是`View`,接下来我们看一下`View.dispatchTouchEveent()`方法:
442+
上面讲了`ViewGroup``dispatchTouchEvent()`有些地方会调用`super.dispatchTouchEvent()`,而`ViewGroup`的父类就是`View`,接下来我们看一下`View.dispatchTouchEvent()`方法:
443443
```java
444444
/**
445445
* Pass the touch screen motion event down to the target view, or this
@@ -531,7 +531,7 @@ public boolean onTouchEvent(MotionEvent event) {
531531
}
532532

533533
// 关于TouchDelegate,文档中是这样说的The delegate to handle touch events that are physically in this view
534-
// but should be handled by another view. 就是说如果两个View, View2在View1中,View1比较大,如果我们想点击
534+
// but should be handled by another view. 就是说如果两个View, View2在View1中,View1比较大,如果我们想点击
535535
// View1的时候,让View2去响应点击事件,这时候就需要使用TouchDelegate来设置。
536536
// 简单的理解就是如果这个View有自己的时间委托处理人,就交给委托人处理。
537537
if (mTouchDelegate != null) {
@@ -542,12 +542,12 @@ public boolean onTouchEvent(MotionEvent event) {
542542

543543
if (((viewFlags & CLICKABLE) == CLICKABLE ||
544544
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
545-
// 这个View可点击
545+
// 这个View可点击
546546
switch (event.getAction()) {
547547
case MotionEvent.ACTION_UP:
548-
// 最好先看DOWN后再看MOVE最后看UP。
548+
// 最好先看DOWN后再看MOVE最后看UP。
549549
// PFLAG_PREPRESSED 表示在一个可滚动的容器中,要稍后才能确定是按下还是滚动.
550-
// PFLAG_PRESSED 表示不是在一个可滚动的容器中,已经可以确定按下这一操作.
550+
// PFLAG_PRESSED 表示不是在一个可滚动的容器中,已经可以确定按下这一操作.
551551
boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
552552
if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
553553
// 处理点击或长按事件
@@ -651,7 +651,7 @@ public boolean onTouchEvent(MotionEvent event) {
651651

652652
// Be lenient about moving outside of buttons, 检查是否移动到View外面了。
653653
if (!pointInView(x, y, mTouchSlop)) {
654-
// 移动到区域外面去了,就要取消点击。
654+
// 移动到区域外面去了,就要取消点击。
655655
// Outside button
656656
removeTapCallback();
657657
if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
@@ -726,4 +726,4 @@ public boolean performClick() {
726726
---
727727

728728
- 邮箱 :charon.chui@gmail.com
729-
- Good Luck!
729+
- Good Luck!

Diff for: SourceAnalysis/AsyncTask详解.md

+20-20
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
AsyncTask详解
22
===
33

4-
`AsyncTask`简单的说其实就是`Handler``Thread`的结合,就想下面自己写的`MyAsyncTask`一样,这就是它的基本远离,当然它并不止这么简单。
4+
`AsyncTask`简单的说其实就是`Handler``Thread`的结合,就像下面自己写的`MyAsyncTask`一样,这就是它的基本原理,当然它并不止这么简单。
55

66
- 经典版异步任务
77

@@ -69,9 +69,9 @@ new AsyncTask<Void, Void, Void>() {
6969
super.onPostExecute(result);
7070
}
7171
}.execute();
72-
类的构造方法中接收三个参数,这里我们不用参数就都给它传Voidnew出来AsyncTask类之后然后重写这三个方法,
73-
最后别忘了执行execute方法,其实它的内部和我们写的经典版的异步任务相同,也是里面写了一个在新的线程中去执行耗时的操作,
74-
然后用handler发送Message对象,主线程收到这个Message之后去执行onPostExecute中的内容。
72+
// 类的构造方法中接收三个参数,这里我们不用参数就都给它传Void,new出来AsyncTask类之后然后重写这三个方法,
73+
// 最后别忘了执行execute方法,其实它的内部和我们写的经典版的异步任务相同,也是里面写了一个在新的线程中去执行耗时的操作,
74+
// 然后用handler发送Message对象,主线程收到这个Message之后去执行onPostExecute中的内容。
7575

7676

7777
//AsyncTask<Params, Progress, Result> ,params 异步任务执行(doBackgroud方法)需要的参数这个参数的实参可以由execute()方法的参数传入,
@@ -120,10 +120,10 @@ new AsyncTask<String, Void, Boolean>() {
120120

121121
}.execute("backup.xml"); //这里传入的参数就是doInBackgound中的参数,会传入到doInBackground中
122122

123-
ProgressDialog有个方法
124-
incrementProgressBy(int num);方法,这个方法能够让进度条自动增加,如果参数为1就是进度条累加1
123+
// ProgressDialog有个方法
124+
// incrementProgressBy(int num);方法,这个方法能够让进度条自动增加,如果参数为1就是进度条累加1。
125125

126-
可以给ProgressDialog添加一个监听dismiss的监听器。pd.setOnDismisListener(DismisListener listener);让其在取消显示后做什么事
126+
// 可以给ProgressDialog添加一个监听dismiss的监听器。pd.setOnDismisListener(DismisListener listener);让其在取消显示后做什么事
127127
```
128128

129129
经过上面两部分,我们会发现`AsyncTask`太好了,他帮我们封装了`Handler``Thread`,当然他内部肯定会有线程池的管理,所以以后我们在开发中对于耗时的操作可以都用`AsyncTask`来搞定的。其实这种做法是错误的。今天发现公司项目中的网络请求都是用`AsyncTask`来做的(刚换的工作)。这样会有严重的问题。
@@ -132,7 +132,7 @@ incrementProgressBy(int num);方法,这个方法能够让进度条自动增加
132132

133133
- `AsyncTask`虽然有`cancel`方法,但是一旦执行了`doInBackground`方法,就算调用取消方法,也会执行完`doInBackground`方法中的内容才会停止。
134134
- 串行还是并行的问题。
135-
`1.6`之前,`AsyncTask`是串行执行任务的。`1.6`的时候开始采用线程池并行处理。但是从`3.0`开始为了解决`AsyncTask`的并发问题,`AsyncTask`又采用一个现成来串行执行任务。(串行啊,每个任务10秒,五个任务,最后一个就要到50秒的时候才执行完)
135+
`1.6`之前,`AsyncTask`是串行执行任务的。`1.6`的时候开始采用线程池并行处理。但是从`3.0`开始为了解决`AsyncTask`的并发问题,`AsyncTask`又采用一个线程来串行执行任务。(串行啊,每个任务10秒,五个任务,最后一个就要到50秒的时候才执行完)
136136
- 线程池的问题。
137137

138138

@@ -171,7 +171,7 @@ If you truly want parallel execution, you can invoke executeOnExecutor(java.util
171171
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
172172
*/
173173
public AsyncTask() {
174-
// 初始化mWorker
174+
// 初始化mWorker
175175
mWorker = new WorkerRunnable<Params, Result>() {
176176
public Result call() throws Exception {
177177
// 修改该变量值
@@ -190,7 +190,7 @@ public AsyncTask() {
190190
@Override
191191
protected void done() {
192192
try {
193-
// 执行完成后的操作
193+
// 执行完成后的操作
194194
postResultIfNotInvoked(get());
195195
} catch (InterruptedException e) {
196196
android.util.Log.w(LOG_TAG, e);
@@ -266,14 +266,14 @@ private static class InternalHandler extends Handler {
266266
}
267267
}
268268
```
269-
我们看到如果判断消息类型为`MESSAGE_POST_RESULT`时,回去执行`finish()`方法,接着看一下`result.mTask.finish()`方法的源码:
269+
我们看到如果判断消息类型为`MESSAGE_POST_RESULT`时,会去执行`finish()`方法,接着看一下`result.mTask.finish()`方法的源码:
270270
```java
271271
private void finish(Result result) {
272272
if (isCancelled()) {
273-
// 如果被取消了就执行onCancelled方法,这就是为什么虽然AsyncTask可以取消,但是doInBackground方法还是会执行完的原因。
273+
// 如果被取消了就执行onCancelled方法,这就是为什么虽然AsyncTask可以取消,但是doInBackground方法还是会执行完的原因。
274274
onCancelled(result);
275275
} else {
276-
// 没被取消就执行oPostExecute方法
276+
// 没被取消就执行oPostExecute方法
277277
onPostExecute(result);
278278
}
279279
mStatus = Status.FINISHED;
@@ -307,7 +307,7 @@ public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec
307307
mStatus = Status.RUNNING;
308308
// 看到我们熟悉的onPreExecute()方法。
309309
onPreExecute();
310-
// 将参数设置给mWorker变量
310+
// 将参数设置给mWorker变量
311311
mWorker.mParams = params;
312312
// 执行了Executor的execute方法并用mFuture为参数,这个exec就是上面的sDefaultExecutor
313313
exec.execute(mFuture);
@@ -331,16 +331,16 @@ private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
331331
从上面的部分能够看出`sDefaultExecutor`是一个`SerialExecutor`对象,好了,接下来看一下`SerialExecutor`类:
332332
```java
333333
private static class SerialExecutor implements Executor {
334-
// 用一个队列来管理所有的runnable。offer是把要执行的添加进来,在scheduleNext中取出来去执行。
334+
// 用一个队列来管理所有的runnable。offer是把要执行的添加进来,在scheduleNext中取出来去执行。
335335
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
336336
Runnable mActive;
337337

338338
public synchronized void execute(final Runnable r) {
339-
// 终于找到了sDefaultExecutor.execute()所真正执行的部分。
339+
// 终于找到了sDefaultExecutor.execute()所真正执行的部分。
340340
mTasks.offer(new Runnable() {
341341
public void run() {
342342
try {
343-
// 就是mFuture的run方法,他会去调用mWorker.call方法,这样就会执行doInBackground方法,执行完后会把返回值用Handler发送出去
343+
// 就是mFuture的run方法,他会去调用mWorker.call方法,这样就会执行doInBackground方法,执行完后会把返回值用Handler发送出去
344344
r.run();
345345
} finally {
346346
scheduleNext();
@@ -354,7 +354,7 @@ private static class SerialExecutor implements Executor {
354354

355355
protected synchronized void scheduleNext() {
356356
if ((mActive = mTasks.poll()) != null) {
357-
// 去取队列中的runnable去执行,这个mActive其实就是mFuture对象。
357+
// 去取队列中的runnable去执行,这个mActive其实就是mFuture对象。
358358
THREAD_POOL_EXECUTOR.execute(mActive);
359359
}
360360
}
@@ -388,7 +388,7 @@ public void run() {
388388
V result;
389389
boolean ran;
390390
try {
391-
// 他会去调用 Callable的call()方法,而上面传入的Callable参数是mWorker。所以这里就会调用mWorker的call方法。
391+
// 他会去调用 Callable的call()方法,而上面传入的Callable参数是mWorker。所以这里就会调用mWorker的call方法。
392392
// 通过这里就和之前我们讲的doInBackground方法联系上了.
393393
result = c.call();
394394
ran = true;
@@ -930,4 +930,4 @@ public abstract class AsyncTask<Params, Progress, Result> {
930930
---
931931

932932
- 邮箱 :charon.chui@gmail.com
933-
- Good Luck!
933+
- Good Luck!

Diff for: SourceAnalysis/LeakCanary源码分析.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ LeakCanary源码分析
33

44
[LeakCanary](https://github.com/square/leakcanary)是一个用于检测内存泄漏的工具,可以用于Java和Android,是由著名开源组织Square贡献。
55

6-
强烈建议使用LeakCanary 2.x版本,更高效、使用更简单,而且没有任何Java代码,它当泄露引用到达5时才会发起heap dump,同时使用了全新的heap parser,减少内存占用,提升速度。只需要在dependencies中加入leakcanary的依赖即可。而且debugimplementation只在debug模式下有效,所以不用担心用户在正式环境下也会出现LeanCanary收集。而且是完全使用kotlin实现了,同时使用了[see Shark](https://square.github.io/leakcanary/shark/)来进行heap内存分析,更节省内存。
6+
强烈建议使用LeakCanary 2.x版本,更高效、使用更简单,而且没有任何Java代码,它当泄露引用到达5时才会发起heap dump,同时使用了全新的heap parser,减少内存占用,提升速度。只需要在dependencies中加入leakcanary的依赖即可。而且debugimplementation只在debug模式下有效,所以不用担心用户在正式环境下也会出现LeakCanary收集。而且是完全使用kotlin实现了,同时使用了[see Shark](https://square.github.io/leakcanary/shark/)来进行heap内存分析,更节省内存。
77

88

99

0 commit comments

Comments
 (0)