《艺术探索》读书笔记(更新中)

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被意外终止时:

  1. Activity会调用onSaveInstanceState()保存数据
  2. 然后Activity会委托Window去保存数据
  3. Window猥琐它的顶级容器去保存数据,顶层容器是一个ViewGroup,一般是DecorView.
  4. 顶层容器一一通知子View来保存数据。

onSaveInstanceState()利用Bundle保存一些数据后,我们可以选择在onCreate()或者onRestoreInstanceState() 中接收这些数据。二者的区别是:

  1. onRestoreInstanceState()一旦被调用,Bundle一定是有值的。
  2. 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中有actioncategorydata
一个Activity可以有多个IntentFilter
一个Intent只要能匹配一组IntentFilter即可。
但是一个Intent必须同时匹配组内IntentFilter内的actioncategorydata

1.11 action的匹配规则

action是一个字符串
一个IntentFilter可以有多个actoin只要Intent中的action能够和IntentFilter中的任何一个action相同,即可匹配成功
如果Intent没有action,匹配失败

总结:Intentaction存在,且和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两部分组成:mimeTypeURI

如果IntentFilter中没有指定URIURI默认值contentfile
所以Intent中的URI部分的scheme必须为content或者file才行。
比如 :

intent.setDataAndType(Uri.parse("file://abc"),"image/png");

同时设置mimeTypeURI必须用setDataAndType 方法。

1.14 匹配时 建议先判断intent是否有Activity能匹配

可以通过PackageMangerresolveActivity 方法 或者 IntentresolveActivity方法判断,找不到会返回null。
这两个方法,第一个参数是intent,第二参数我们要使用intflag值,为MATCH_DEFAULT_ONLY.

PackageManger还有一个queryIntentActivities方法,它返回一个List<ResolveInfo>.

第四章 View的工作原理

第一时间获取View的宽高:

  1. Activity/View#onWindowFocusChanged();
  2. view.post(Runnable)
  3. ViewTreeObserver
  4. 手动view.measure().

自定义View注意事项:

  1. 让View支持wrap_content
  2. View支持padding。ViewGroup支持padding和子View的margin.(View在onDraw中处理。ViewGroup需要在onMeasure()和onLayout()中处理)
  3. View内部可以使用post…方法替代handler.
  4. 如果有线程、动画等,需要停止,防止内存泄漏。需要使用onDetachedFromWindow()
  5. 嵌套滑动

第9章 四大组件的工作过程

四大组件除了广播,其他三种都必须在AndroidManifest里注册。 对于BroadcastReceiver 可以在AndroidManifest里静态注册,也可以在代码中动态注册。

调用时,ContentProvier借助Uri,其他借助Intent。

IApplicationThread 这个Binder接口的实现类完成了和Activity、Service启动、停止相关的功能。

Activity

启动Activity:
startActivity()->
ContextImpl.startActivity()->
Instrumentation->
ActivityManagerService(ActivityManagerNative.getDefault() )
…..
最终回调app.thread.scheduleLaunchActivity().
回到ActivityThread里的ApplicationThreadscheduleLaunchActivity()方法。


值得一提的是,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。
例如ServiceConnectionBroadcastReceiver``,ContentProvider

第11章 Android的线程和线程池

AsyncTask注意事项:

  1. AsyncTask的类必须在主线程中加载,意味着第一次使用到AsyncTask必须在主线程。(4.1以上版本已由系统自动完成。在ActivityThread中调用AsyncTask.init方法。查看23+的源码,内部Handler强制使用Looper.mainLooper();)
  2. Asynctask的创建必须在主线程。
  3. execute()方法必须在主线程中调用。
  4. 不要直接调用onPostExecute()….等回调。
  5. 一个AsyncTask只能执行一次,只能调用一次execute()方法,否则crash。
  6. 1.6之前,AsyncTask是串行执行任务的。从1.6开始,改为线程池并行处理任务。但从3.0开始,为避免并发错误,又改为了串行执行。但提供了executeOnExecutor()来并行执行任务。

以上是关于《艺术探索》读书笔记(更新中)的主要内容,如果未能解决你的问题,请参考以下文章

《android开发艺术探索》读书笔记--动画

《android开发艺术探索》读书笔记(十三)--综合技术

《android开发艺术探索》读书笔记--WindowManager

《android开发艺术探索》读书笔记(十五)--Android性能优化

《android开发艺术探索》读书笔记--Android的消息机制

Android开发艺术探索读书笔记——进程间通信