《Android开发艺术探索》作者:任玉刚
第一章 Activity的生命周期和启动模式
activity跳转的时候,如果新activity采用了透明主题,那么当前activity不会回调
onStop()
onSaveInstanceState()
调用在onStop()
之前,onRestoreInstanceState()
调用在onCreate()
之后一个进程脱离四大组件而独自运行在后台中,很容易被系统杀死(从侧面也理解出,与用户无交互的功能应放在service,而不是单例中)
-
singleTask的匹配模式为:先找符合的任务栈
TaskAffinity
,再找相同的实例,另外,要启动的activity为singleTask,如果某栈中存在该实例,就会把该栈整个移动到前台栈中,比如: 前台栈存在AB实例,后台栈存在CD实例, 现在启动D,那么就会变成前台栈为CD,后台栈为AB,书中图示如下:
需要注意的是,TaskAffinity
和allowTaskReparenting
结合使用的时候,情况会比较复杂,这里引用书中原话:
当一个应用A启动了应用B的某个Activity后,如何这个Activity的allowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中
(ps: TaskAffinity默认为应用包名)
- intentFilter的匹配规则
action
: intent中的action只要有一个和过滤规则中的任何一个action相同即可匹配成功
category
: intent中可以没有category,直接匹配成功,但是如果Intent中存在category那么每一个都要和过滤规则中匹配上才成功
data
: 匹配规则与action类似
注意隐式调用中,android默认会加上android.intent.categiry.DEFAULT
,所以匹配的activity的Intent-filter中必须增加该category
第二章 IPC机制
Android应用内开启多进程模式只有一种方法,就是给四大组件在AndroidManifest中指定
android:process属性
Parceable
主要用于内存中序列化,对于磁盘存储以及网络传输建议使用Serializable
所有可以在Binder中传输的接口都需要继承IInterface接口
binderDied() 和 onServiceDisconnected()区别???
onServiceDisconnected在客户端的UI线程中被回调,而binderDied在客户端的Binder线程池中被回调,两者同样可以用于重连服务的场景transact和onTransact的区别???
跨进程通信的方法:
aidl
,socket
,contenprovider
,文件共享
,intent附加extrax信息(bundle)
,messager
aidl中,客服端调用远程服务的方法,被调用的方法运行在服务端的Binder线程池中,相反服务端调客户端也一样
aidl中,接口的注册和解注册使用RemoteCallbackList实现
绑定binder的权限验证方式:
permission
,packageName
多service的情况,可以使用binder连接池处理
第三章 View的事件体系
getX()
和getY()
: 返回相对于当前View左上角的x和y坐标
getRaw()Y
和getRawY()
:返回相对于手机屏幕左上角的x和y坐标TouchSlop为系统所能识别的最小滑动距离,即小于这个数值的距离不认为为滑动,获取方式:
ViewConfiguration.get(getContext()).getScaledTouchSlop()
-
mScrollX/mScrollY
指的是view的边缘和view内容边缘的滑动距离,这个通过下面图来理解就好
requestDisallowInterceptTouchEvent
方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN
事件除外触摸事件分发机制图
第四章 View的工作原理
measureSpec
不是唯一由LayoutParams
决定的,LayoutParams需要和父容器一起才能决定View的MeasureSpec,从而进一步决定View的A宽/高view最终的大小是在layout阶段确定的(参考第五点)
一个比较好的习惯是在onLayout方法中去获取View的测量宽/高或者最终宽/高
获取view测量的宽/高方法
Activity/View#onWinndowFocusChanged
view.post(runnable)
VieTreeObserver
getMeasuredWidth和getWidth的区别?
getMeasuredWidth
:是测量时赋值
getWidth
:是布局时赋值(右上角左边减去左上角左边)
getMeasuredWidth
和getWidth
不一定相等view有一个特殊的方法setWillNotDraw,该方法是用于对于没有绘制的view进行优化的,如果明确知道一个viewgroup需要调用onDraw的时候,需要显示的关闭这个标记位
7 自定义view须知
让View支持wrap_content
如果有必要,让你的View支持padding
尽量不要在View中使用Handler,除非必要情况
View中如果有线程/动画,需要及时停止,参考View#onDeteachedFromWindow
View带有滑动嵌套情形时,需要处理好滑动冲突
第五章 理解RemoteViews
-
PendingIntent
的匹配规则:如果两个PendingIntent它们内部的Intent相同并且requestCode也相同,那么这两个PendingIntent就是相同的,其中Intent的匹配规则是ComponentName和intent-filter都相同,排除Extras
第六章 Android的Drawable
- 一般来说drawable是没有大小概念的,但他可以设置固有宽/高,并通过
getIntrinsicWidth
和getIntrinsicHeight
这两个方法获取
第七章 Android动画深入分析
View动画中的shareInterpoliator属性表示: 动画集合是否共享一个插值器
activity的切换效果可以在
startActivity(intent)/finish()
之后调用overridePendingTransition(int enterAnim,int exitAnim)
使用动画的过程中建议开启硬件加速,这样会提高动画的流畅性
扩展:
补间动画的实现原理:
1.调用view的startAnimation会执行invalidate(true),然后就会遍历整个树图,然后找到viewrootimpl,接着执行它的performTraversals,这个就在正常view绘制的三大流程入口
2.其中在view绘制的时候调用的是draw(三个参数),里面执行applyLegacyAnimation,该方法最终会执行到子类的applyTransformation方法,就是具体的矩阵变换算法中,另外还会返回一个动画是否结束的标志,如果没有结束则重新走invalidate()继续绘制视图
3.applyTransformation实际操作的对象是canvas,而不是view中的具体属性值,所以补间动画不会改变view的真正大小和位置,只是对他的canvas做矩阵变换
第八章 理解Window和WindowManager
window有三种类型:
应用window: 层级为1~99
子window:层级为1000~1999
系统wind: 层级为2000~2999window进行添加view,更新view,删除view的操作实际是通过windowManager实现的,而windownManager又委托给WindowManagerGlobal来进行,golbal主要分如下几步来实现:
检查参数是否合法,如果是子window那么还需要调整一些布局参数
创建viewrootimpl并将view添加到列表中(其内部有 mViews,mRoots,mParams等集合,分别为所有window对应的view,所有window对应的viewrootimpl,所有window的布局参数)
最后通过viewrootimpl来更新界面并完成window的添加,其实际是通过WindowSession访问WindowManagerService进行window的添加-
window添加流程时序图
第九章 四大组件的工作工程
看得云里雾里
第十章 Android的消息机制
ActivityThread也就是UI线程,在创建的时候就会初始化Looper,这也是在主线程中默认可以使用Handler的原因
ThreadLocal是一个线程内部的数据存储类,不同线程中的数据相互独立互不干扰
handler处理消息机制主要是: handler向Messagequeue插入了一条消息,Messagequeue的next方法会返回这条消息给looper,looper收到消息后就开始处理,最后又交回给handler处理,即handler的dispatchMessage方法会被调用
第十一章 Android的线程和线程池
1.ThreadPoolExecutor构造方法的参数意义:
corePoolSize
: 最大核心线程数,一直存活,但是如果设置了allowCoreThreadTimeOut为true,会有超时策略
maximumPoolSize
:线程池所能容纳的最大线程数
keepAliveTime
: 非核心线程闲置时的超时时长,allowCoreThreadTimeOut为true时,核心线程数也会被回收
unit
:超时时间单位
workQueue
: 任务队列大小
threadFactor
:线程共创,为线程池提供创建新线程的功能
常用四类线程池
FixedThreadPool
: 快速响应外界的请求
CacgedTgreadPool
:适合执行大量的耗时较少的任务
ScheduledThreadPool
: 主要用于执行定时任务和具有固定周期的重复任务
SingleThreadExecutor
:确保所有的任务都在同一个线程中按顺序执行AsyncTask实际是封装了Thread和Handler,IntentService实际是封装了HandlerThread和Handler
第十二章 Bitmap的加载和Cache
- 采用BitmapFactory.Onptions来高效加载Bitmap,其中涉及的参数:
inJustDecodeBounds
: 设为true时,BitmapFactory只会解析图片的原始宽/高信息,并不会真正地加载图片,所以这个操作是轻量级的,通常用于需要修改inSampleSize(采样率)的使用
inSampleSize
: 采样率,小于1无效,尽量使用2的指数,bitmap的像素/内存占用缩放比例为 1/(inSampleSize的2次方)