Tasks and Back stack 详解:https://www.jianshu.com/p/833de0674f80
Android Task相关属性详解:https://www.jianshu.com/p/6dc5154b08b8
实验:
1.activityA的launchMode设置为singleTask,调用activity顺序是:A=>A=>B=>A,打印日志:
10-09 14:28:15.776 15610-15610/pers.peng.test D/activity-A: onCreate taskId=1366
10-09 14:28:15.776 15610-15610/pers.peng.test D/activity-A: onStart taskId=1366
10-09 14:28:21.376 15610-15610/pers.peng.test D/activity-A: onNewIntent taskId=1366
10-09 14:28:22.686 15610-15610/pers.peng.test D/activity-B: onCreate taskId=1366
10-09 14:28:22.686 15610-15610/pers.peng.test D/activity-B: onStart taskId=1366
10-09 14:28:23.076 15610-15610/pers.peng.test D/activity-A: onStop taskId=1366
10-09 14:28:23.906 15610-15610/pers.peng.test D/activity-A: onNewIntent taskId=1366
10-09 14:28:23.906 15610-15610/pers.peng.test D/activity-A: onStart taskId=1366
10-09 14:28:24.296 15610-15610/pers.peng.test D/activity-B: onStop taskId=1366
10-09 14:28:24.296 15610-15610/pers.peng.test D/activity-B: onDestroy taskId=1366
A和B位于同一个返回栈中,在B跳转到A时,不会新建A的实例,而是重用已存在于栈中的实例A,并将其上面的activity全部弹出,将A移到栈顶。此时按返回键,会退出程序。
2.activityA的launchMode设置为singleInstance,调用activity顺序是:A=>A=>B=>C=>A,打印日志:
10-09 14:57:05.466 16406-16406/pers.peng.test D/activity-A: onCreate taskId=1398
10-09 14:57:05.466 16406-16406/pers.peng.test D/activity-A: onStart taskId=1398
10-09 14:57:07.826 16406-16406/pers.peng.test D/activity-A: onNewIntent taskId=1398
10-09 14:57:09.046 16406-16406/pers.peng.test D/activity-B: onCreate taskId=1399
10-09 14:57:09.046 16406-16406/pers.peng.test D/activity-B: onStart taskId=1399
10-09 14:57:09.756 16406-16406/pers.peng.test D/activity-A: onStop taskId=1398
10-09 14:57:10.426 16406-16406/pers.peng.test D/activity-C: onCreate taskId=1399
10-09 14:57:10.426 16406-16406/pers.peng.test D/activity-C: onStart taskId=1399
10-09 14:57:10.816 16406-16406/pers.peng.test D/activity-B: onStop taskId=1399
10-09 14:57:12.056 16406-16406/pers.peng.test D/activity-A: onNewIntent taskId=1398
10-09 14:57:12.056 16406-16406/pers.peng.test D/activity-A: onStart taskId=1398
10-09 14:57:12.856 16406-16406/pers.peng.test D/activity-C: onStop taskId=1399
指定为singleInstance的activity会在单独的任务中打开,且是该任务唯一仅有的成员。按返回键返回的顺序是:A=>C=>B=>退出程序。
1.常见情况下的生命周期分析
(1)启动activityA,跳转到activityB,按返回键返回到activityA,A的方法回调如下:onCreate->onStart->onResume->onPause->onStop->onRestart->onStart->onResume
(2)启动activityA,弹出dialog,按返回键回到activityA,A的方法回调如下:onCreate->onStart->onResume->onPause->onResume
(3)启动activityA,按返回键结束程序,A的方法回调如下:onCreate->onStart->onResume->onPause->onStop->onDestroy
(4)启动activityA,按home键回到启动界面,A的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop
(5)启动activityA,旋转屏幕,A的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop->onDestroy->onCreate->onStart->onResume
onStart和onResume,onPause和onStop的区别?
答:onStart和onStop是从Activity是否可见这个角度来回调的,而onResume和onPause是从Activity是否位于前台这个角度来回调的,除了这种区别,在实际使用中没有其他明显区别。
假设当前Activity为A,如果从A中跳转到ActivityB,那么B的onResume和A的onPause哪个先执行?
答:回调顺序为:A onPause->B onCreate->B onStart->B onResume->A onStop
。
为了使新Activity尽快显示,是否要把所有资源回收放在onStop中?
答:不是。如果在Activity A中打开了如照相机等独占设备,需要在onPause中释放,否则Activity B将不能正常启动照相机。所以一般在onPause中进行关闭独占设备,关闭动画等,防止Activity B需要用到这些资源,而在onStop中释放其他资源。
关于每个回调方法的详细信息见:https://developer.android.google.cn/reference/android/app/Activity
2.异常情况下的生命周期分析
异常情况主要包括旋转屏幕,按home键,内存不足导致低优先级的Activity被杀死等,这些情况下onSaveInstanceState会被调用,如果activity销毁重建还会调用onRestoreInstanceState。onSaveInstanceState会在onPause或onStop之前执行,onRestoreInstanceState会在onStart和onResume之间执行。在onSaveInstanceState和onRestoreInstanceState中,系统自动为我们做了一定的恢复工作。当Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后为我们恢复这些数据,比如文本框中用户输入的数据,ListView滚动的位置等。
如果当某项内容发生改变后,我们不想系统重新创建Activity,可以给Activity指定configChanges属性。比如不想让Activity在屏幕旋转的时候重新创建,就可以给configChanges属性添加orientation这个值,如下所示。
android:configChanges=“orientation”
如果想指定多个值,可以用“|”连接起来。系统配置中所含的项目是非常多的。configChanges的项目和含义见:https://blog.csdn.net/weixin_36039900/article/details/80166786
——《Android开发艺术探索》
Activity标签属性:https://www.cnblogs.com/tsingke/p/9074628.html
在activityB标签下增加:android:parentActivityName=".activityA"
,从activityA跳转到activityB,点击activityB actionbar上的返回箭头返回到activityA,activityA的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop->onDestroy->onCreate->onStart->onResume。
在activityA标签下增加:android:launchMode="singleTop"
,从activityA跳转到activityB,点击activityB actionbar上的返回箭头返回到activityA,activityA的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop->onNewIntent->onRestart->onStart->onResume。
IntentFilter中的过滤信息有action,category和data。隐式调用的Intent可以设置一个action,多个category和一个data。如果activityA的intent-filter如下:
<intent-filter>
<action android:name="pers.peng.test.action.A"></action>
<action android:name="pers.peng.test.action.B"></action>
<category android:name="pers.peng.test.category.A"></category>
<category android:name="pers.peng.test.category.B"></category>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="http"/>
<data android:mimeType="image/*"/>
<data android:mimeType="audio/*"/>
</intent-filter>
隐式调用的Intent的匹配规则如下:
action:Intent中的action要存在且必须和过滤规则中的任何一个action相同即可匹配成功,针对上面的过滤规则,只能使用 intent.setAction("pers.peng.test.action.A")
或 intent.setAction("pers.peng.test.action.B")
。另外,action区分大小写。
category:Intent中的category必须是过滤规则中category的子集,如果过滤规则中有
,intent中可以没有category,因为系统在调用startActivity或startActivityForResult的时候会默认为Intent加上"android.intent.category.DEFAULT"。
data:data的语法如下所示:
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string"/>
data包括两部分:mimeType和URI。data的匹配规则和action类似,Intent中必须含有data数据且要和过滤规则中的某一个data相同。针对上面的过滤规则,只能使用 intent.setDataAndType(Uri.parse("http://xxx"),"audio/xxx")
或intent.setDataAndType(Uri.parse("http://xxx"),"image/xxx")
。
除此以外,还需要注意两点:
1.如果过滤规则中同时存在mimeType和URI,要为Intent指定data,只能调用setDataAndType方法,不能先调用setData再调用setType,因为这两个方法彼此会清除对方的值,这个看源码就很容易理解,比如setData:
public Intent setData(Uri data){
mData = data;
mType = null;
return this;
}
setType同理。如果过滤规则中没有指定URI,可以使用setType,也可以使用intent.setDataAndType(Uri.parse("content://xxx"),"xxx/xxx")
和intent.setDataAndType(Uri.parse("file://xxx"),"xxx/xxx")
,因为content和file是没有指定URI时的默认值。
2.intent-filter中的data有两种写法,除了上面的那种,还可以写成:
<data android:scheme="http" android:mimeType="image/*"/>
<data android:mimeType="audio/*"/>
两种写法是一样的,不要以为可以使用setType("audio/xxx")
。
Android中Action和Category常量表:https://cloud.tencent.com/developer/article/1330887
最后,当我们通过隐式方法启动一个Activity的时候,可以做一下判断,看是否有Activity能够匹配我们的隐式intent,如果不做判断可能会出错。判断方法有三种:采用PackageManager的resolveActivity方法和queryIntentActivities或者Intent的resolveActivity方法,它们的方法原型如下:
public abstract List< ResolveInfo > queryIntentActivities(Intent intent,int flags);
public abstract ResolveInfo resolveActivity(Intent intent,int flags);
public abstract ComponentName resolveActivity(PackageManager pm);
flags使用MATCH_DEFAULT_ONLY这个标记位。
——《Android开发艺术探索》
Android 成长笔记1——activity与context:https://www.jianshu.com/p/3172baa3d74d
Application中的Context和Activity中的Context各自的使用场景:
copy别人的话:凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以。
在Android中,可以通过继承Application类来实现应用程序级的全局变量,这种全局变量方法相对静态类更有保障,直到应用的所有Activity全部被destory掉之后才会被释放掉。
示例(kotlin):
class App : Application() {
companion object {
var instance: App by DelegatesExt.notNullSingleValue()
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
object DelegatesExt {
fun <T> notNullSingleValue() = NotNullSingleValueVar<T>()
}
class NotNullSingleValueVar<T> {
private var value: T? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
value ?: throw IllegalStateException("${property.name} not initialized")
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = if (this.value == null) value
else throw IllegalStateException("${property.name} already initialized")
}
}
不要忘记要在Manifest中application标签下加上android:name=".App"
。
Android Activity切换动画(进入和退出):https://www.jianshu.com/p/8bda45eef4f1