Android开发艺术探索 第一章
1.1生命周期
这个章节主要讲生命周期和源码调用分析,需要注意到的是,活动之间的跳转,在onPause不要进行重量级别操作。
-
Activity A 的onPause() → Activity B的onCreate() → onStart() → onResume() → Activity A的onStop();如果B是透明主题又或则是个DialogActivity,则不会回调A的onStop;
-
使用onSaveInstanceState()保存简单,轻量级的UI状态
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
//step 1: 创建LoadedApk对象
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
... //component初始化过程
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//step 2: 创建Activity对象
Activity activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
...
//step 3: 创建Application对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
//step 4: 创建ContextImpl对象
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
//step5: 将Application/ContextImpl都attach到Activity对象
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
...
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
//step 6: 执行回调onCreate
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart(); //执行回调onStart
r.stopped = false;
}
if (!r.activity.mFinished) {
//执行回调onRestoreInstanceState
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
...
r.paused = true;
mActivities.put(r.token, r);
}
return activity;
}
异常生命周期处理
资源改变导致活动重建,例如横竖屏切换,VIEW的状态会保存,具体可以看每个View的onSaveInstanceState保存了哪些状态。
横竖屏切换也可以设置android:configChanges="orientation"不改变,会回调onConfigurationChanged方法
资源不足也会导致优先级低的活动被杀死。前台活动优先级最高,最低是后台活动。
1.2启动模式
1. standard 标准模式,每次创建都会重新创建一个实例。用ApplicationContext启动会报错,因为任务栈是activity的类型,建议不存在任务栈时候,会用singleTask模式启动,创建新的任务栈,标记位FLAG_ACTIVITY_NEW_TASK。
2. singleTop 栈顶复用模式,处于任务栈顶会被复用,不会生成新的实例,而会调用onNewIntent方法,通过这个方法获取请求的信息。FLAG_ACTIVITY_SINGLE_TOP
3. singleTask 栈内复用模式,处于任务栈顶内被复用,不会生成新的实例,而会调用onNewIntent方法,通过这个方法获取请求的信息。如果任务栈不存在,会创建新的任务栈放入新的活动实例。等同于FLAG_ACTIVITY_NEW_TASK。
4.singleInstance 单实例模式,加强版singleTask,处于单独的任务栈中,后续请求均不会生成新的实例,除非独立的任务栈被系统销毁。
动态的Flags
1.FLAG_ACTIVITY_NEW_TASK 和singleTask一样
2.FLAG_ACTIVITY_SINGLE_TOP 和singleTop一样
3.FLAG_ACTIVITY_CLEAR_TOP 和FLAG_ACTIVITY_NEW_TASK一起出现,和singleTask类似,栈内在它上面的活动都要出栈。
4.FLAG_ACTIVITY_EXCLUDE_REOM_RECENTS 不会出现在历史记录当中,和 android:excludefromrecents="true" 一样
活动都会放入任务栈当中,后进先出原则。
需要理解任务栈,TaskAffinity,这个参数标识一个活动需要的任务栈名称,一般默认是包名,也可以单独为活动指定TaskAffinity属性。
TaskAffinity主要和singleTask或者allowTaskReparenting使用,其他模式没有意义。
singleTask里面的任务栈指的就是TaskAffinity名称相同的任务栈。
allowTaskReparenting比较复杂,当A启动B,那边B启动后,会把A转移到B任务栈中。比如两个不同应用A和B,A启动B应用里面的一个C活动,那边C进入的B的任务栈,而不是A的,因为包名都不一样,这个时候启动B,会直接进入C活动,而不是B的主活动。
实现方式:
AndroidMenifest中定义
android:launchMode="standard"
代码中定义
Intent intent=new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1.3 IntentFilter匹配规则
显示调用和隐式调用。
action匹配规则:必须是字符串,匹配完全一样。如果存在多个,匹配一个就算成功。
cetegory匹配规则:必须是字符串,如果有,每个都需要匹配一样。默认是是android.intent.cetegory.DEFAULT.
data匹配规则:和action类似,结构比较复杂,分为mimeType(媒体类型)和URI。
scheme:URI模式,比如http、file、content
host:URI主机名
port:URI端口
Path、pathPattern、pathPrefix:都是代表路径,第一个是完整路径,第二个可以正则匹配,第三个表示路径前缀信息。
过滤规则:<data android:mimeType="image/* /> 匹配所有类型的图片
<data android:mimeType="video/mpeg" android:scheme="http"...
data android:mimeType="audio/mpeg" android:scheme="http"... /> //符合其中一条即可
PackageManager的resolveActivity方法可以返回最佳符合活动,也可以用queryIntentActivites方法查询所有符合的活动。