《艺术探索》读书笔记(更新中)
Posted 张旭童
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《艺术探索》读书笔记(更新中)相关的知识,希望对你有一定的参考价值。
前言
最近没有写什么新博文,
一是太忙了,而且马上有新的挑战来到。
二是赶上过年期间。
三是没有什么太好的题材写。
四是自己在充电在半闭关学习。
计划下篇博文本月更新吧,题材从下列中出一个 Retrofit 、组件化、自定义View
最近重读《艺术探索》,将其中一些对我有用的、我仍然不知道的、或者觉得容易混淆的知识点整理出来。
部分也有可能是我自己总结整理出来的经验,一并放在里面。
第1章 Activity的生命周期和启动模式
1.1 生命周期,Activity从 不可见变成可见,onRestart()
会重新调用(按Home,从别的Activity返回)
1.2 但onPause()
方法回调后,才会执行新Activity的onCreate()
1.3 关于onSaveInstanceState()
。
back返回时不调用。
Home时会被调用。
启动一个新的Activity时 会被调用。
并不是和onRestoreInstanceState()
成对出现。
出现在 onStop()
前面.
(书上说和onPause()
没有关系,可能在前可能在后。)
该方法只有在Activity 即将可能被销毁,并且有机会重新的创建显示才会调用。
按Home、启动新Activity,这个Activity都是后台Activity了,可能被销毁,但是销毁后,还是有机会重新创建的,所以会回调。
而正常的back,不会会重新创建了,所以不回调。
1.4 关于onRestoreInstanceState()
。
出现在onStart()
后面。
1.5 关于上述两个方法
系统已经在这两个方法中,onRestoreInstanceState()
onSaveInstanceState()
.为我们做了一定的恢复工作,例如ListView的滚动位置,EditText的输入数据。
针对每一个View,系统能为我们自动恢复哪些数据,可以查看View的源码,也有onRestoreInstanceState()
onSaveInstanceState()
方法。
关于保存和恢复,是一个典型的委托思想,工作流程如下:
Activity被意外终止时:
- Activity会调用
onSaveInstanceState()
保存数据 - 然后Activity会委托Window去保存数据
- Window猥琐它的顶级容器去保存数据,顶层容器是一个ViewGroup,一般是DecorView.
- 顶层容器一一通知子View来保存数据。
onSaveInstanceState()
利用Bundle保存一些数据后,我们可以选择在onCreate()
或者onRestoreInstanceState()
中接收这些数据。二者的区别是:
onRestoreInstanceState()
一旦被调用,Bundle一定是有值的。onCreate()
里要对Bundle判空。
官方建议是前者。
1.6 singleTop、singleTask、singleInstance
生命周期,onPause()
->onNewIntent()
->onResume()
1.7 singleTask 默认具有 cleaerTop的效果
1.8 singleInstance 只能单独的位于一个任务栈中。
1.9 TaskAffinity
这个参数标识了一个Activity所需要的任务栈的名字。
默认情况下,所有Activity所需的任务栈的名字是 应用的包名。
形式为aaa.bbb.ccc 。
TaskAffinity
主要和singleTask启动模式
或者allowTaskReparenting属性
配对使用。
1.10 IntentFilter的匹配规则(隐式调用)
IntentFilter
中有action
、category
、data
。
一个Activity
可以有多个IntentFilter
。
一个Intent
只要能匹配一组IntentFilter
即可。
但是一个Intent
必须同时匹配组内该IntentFilter
内的action
、category
、data
。
1.11 action的匹配规则
action
是一个字符串。
一个IntentFilter
内可以有多个actoin
,只要Intent
中的action
能够和IntentFilter
中的任何一个action
相同,即可匹配成功。
如果Intent
中没有action
,匹配失败。
总结:Intent
中action
存在,且和IntentFilter
中一个action
相同。
1.12 category的匹配规则
category
是一个字符串。
和action
不同。Intent
中如果含有category
,则所有category
必须和IntentFilter
中的一个category
匹配。
如果Intent
中没有category
,也能匹配成功。
原因是系统在调用startActivity
或者startActivityForResult
时,默认会为Intent
加上"android.intent.category.DEFAULT"
的category
。
所以我们的Activity
若想支持隐式调用,则必须要加上这个category
。
1.13 data 的匹配规则
和action
类似。如果IntentFilter
中定义了data
,那么Intent
中必须也要有匹配的data
。
data结构:
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
andorid:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string" />
data
由两部分组成:mimeType
和URI
。
如果IntentFilter
中没有指定URI
,URI
的默认值是content
和file
。
所以Intent
中的URI
部分的scheme
必须为content
或者file
才行。
比如 :
intent.setDataAndType(Uri.parse("file://abc"),"image/png");
同时设置mimeType
和URI
必须用setDataAndType
方法。
1.14 匹配时 建议先判断intent是否有Activity能匹配
可以通过PackageManger
的resolveActivity
方法 或者 Intent
的resolveActivity
方法判断,找不到会返回null。
这两个方法,第一个参数是intent
,第二参数我们要使用int
的flag
值,为MATCH_DEFAULT_ONLY
.
PackageManger
还有一个queryIntentActivities
方法,它返回一个List<ResolveInfo>
.
第四章 View的工作原理
第一时间获取View的宽高:
- Activity/View#onWindowFocusChanged();
- view.post(Runnable)
- ViewTreeObserver
- 手动view.measure().
自定义View注意事项:
- 让View支持wrap_content
- View支持padding。ViewGroup支持padding和子View的margin.(View在onDraw中处理。ViewGroup需要在onMeasure()和onLayout()中处理)
- View内部可以使用post…方法替代handler.
- 如果有线程、动画等,需要停止,防止内存泄漏。需要使用onDetachedFromWindow()
- 嵌套滑动
第9章 四大组件的工作过程
四大组件除了广播,其他三种都必须在AndroidManifest里注册。 对于BroadcastReceiver 可以在AndroidManifest里静态注册,也可以在代码中动态注册。
调用时,ContentProvier借助Uri,其他借助Intent。
IApplicationThread 这个Binder接口的实现类完成了和Activity、Service启动、停止相关的功能。
Activity
启动Activity:
startActivity()
->
ContextImpl.startActivity()
->
Instrumentation
->
ActivityManagerService(ActivityManagerNative.getDefault() )
…..
最终回调app.thread.scheduleLaunchActivity()
.
回到ActivityThread
里的ApplicationThread
的scheduleLaunchActivity()
方法。
值得一提的是,ApplicationThread extends ApplicationThreadNative
.
而public abstract class ApplicationThreadNative extends Binder implements IApplicationThread
熟悉Aidl的,一眼可以看出,ApplicationThreadNative
就是AIDL生成的Stub类。
在其内部还有一个ApplicationThreadProxy
,和AIDL生成的Proxy类一样。内部存储Native
,通过Binder机制,IPC调用Native
的方法。
class ApplicationThreadProxy implements IApplicationThread
(此时仍在Binder线程池中)scheduleLaunchActivity()
发送消息
->ActivityThread.H.handleMessage()
(切换到主线程)
->ActivityThread.handleLaunchActivity()
->ActivityThread.performLaunchActivity()
(1 利用反射构造Activity 和 2 Application、3 回调Application的onCreate() 4 创建ContextImpl,5 调用Activity.attach()关联Activity和ContextImpl. 6 调用Activity的onCreate() )
->ActivityThread.handleResumeActivity()
(显示界面 ,将View add 进Window中)
Service
运行在主线程。 有启动、和绑定两种状态(可以并存)。停止服务通过 stopService 和unBindService.
startService()过程:
Activity基本一致,
(此时仍在Binder线程池中)ActivityThread.ApplicationThread.scheduleCreateService)
发送消息
->ActivityThread.H.handleMessage()
(切换到主线程)
->ActivityThread.handleCreateService()
(1 反射构造Service 2 创建ContextImpl 3 得到Application(可能是构造) 4 调用service.attach()关联Service和ContextImpl和Application 5 回调Service的onCreate()方法 6,缓存Service至Map里,key是Binder对象(ServiceRecord))
Service的onStartCommand()是在随后由AMS回调scheduleServiceArgs()
->handleServiceArgs()
(1 从缓存里取出Service 2 回调onStartCommmand()
)
bindService()过程:
和前述过程基本一致
但是在bindService(Intent,ServiceConnection,int)
中传入的ServiceConnection
对象,
会在ContextImpl.bindServiceCommon()
中被关联转化成一个Binder对象。(因为要跨进程和AMS通信)
->得到待启动Service的进程信息,传入ams,进入ams...
->也会执行onCreate()
的流程。
->ApplicationThread.scheduleBindService()(此时处于被启动、绑定服务的进程)
->handleBindService()
(1 从缓存里取出Service 2 回调onBind() 3 AMS.publishService(),
传入onBind返回的Binder对象,回调告诉客户端ServiceConnection.onServiceConnected()
)
->回到AMS.publishService()
->在上文的和ServiceConnection
关联的Binder中回调。利用请求绑定服务进程的activityThread.post一个消息,将进程和线程切换。回调onBind()返回的Binder对象给onServiceConnected()
BroadcastReceiver
动态注册的Receiver需要注销。
动态注册过程和Service,bind 过程类似。
参数BroadcastReceiver
要转换成一个Binder对象,传递给AMS。
发送的过程:
向AMS发送一个异步请求。
(3.1+,默认会对intent追加一个flag,忽略已经停止的引用。)
AMS找到匹配的Receiver(Binder对象),内部会利用注册Receiver的activityThread.post一个消息,将进程和线程切换。
ContentProvider
内部的insert、delete、update、query 要处理好 线程同步。 因为这几个方法是在Binder线程池中被调用的。
当ContentProvider所在的进程启动时,ContentProvider会同时启动,并发布到AMS中。此时ContentProvider的onCreate()先于Application的onCreate执行。
访问ContentProvider
需要通过ContentResolver
,它是一个抽象类,实现是ApplicationContentResolver。
ApplicationContentResolver
拿Provider时,
**如果是同进程的,那么App一启动就已经注册了。
如果是其他进程的,通过AMS去查。**
拿到的Provider**其实是一个Binder对象,而其中的方法 ,如query,是直接执行的,所以是直接在服务端的Binder线程池中执行。**
总结:
所有的异步回调接口类,最终都会被转换成一个Binder类用于AMS的IPC。
例如ServiceConnection
,BroadcastReceiver``,ContentProvider
第11章 Android的线程和线程池
AsyncTask注意事项:
- AsyncTask的类必须在主线程中加载,意味着第一次使用到AsyncTask必须在主线程。(4.1以上版本已由系统自动完成。在ActivityThread中调用AsyncTask.init方法。查看23+的源码,内部Handler强制使用Looper.mainLooper();)
- Asynctask的创建必须在主线程。
- execute()方法必须在主线程中调用。
- 不要直接调用onPostExecute()….等回调。
- 一个AsyncTask只能执行一次,只能调用一次execute()方法,否则crash。
- 1.6之前,AsyncTask是串行执行任务的。从1.6开始,改为线程池并行处理任务。但从3.0开始,为避免并发错误,又改为了串行执行。但提供了executeOnExecutor()来并行执行任务。
以上是关于《艺术探索》读书笔记(更新中)的主要内容,如果未能解决你的问题,请参考以下文章
《android开发艺术探索》读书笔记--WindowManager
《android开发艺术探索》读书笔记(十五)--Android性能优化