Back键:onPause → onSaveInstanceState → onStop → onDestroy
Home键:onPause → onStop / onRestart → onStart → onResume
锁屏: onPause → onSaveInstanceState → onStop / onRestart → onStart → onResume
A启动B:A:onPause → B:onCreate → B:onStart → B:onResume → A:onSaveInstanceState → A:onStop → A:onDestroy(A是否调用finish)
被打断时(如接电话):onPause → onSaveInstanceState → onStop / onRestart → onStart → onResume
横竖屏切换 Activity被销毁:onPause → onSaveInstanceState(与onPause没有时序关系,可能在之前,也可能在之后) → onStop → onDestroy
Activity被重新创建:onCreate → onRestoreInstanceState → onStart → onResume
当不想Activity被重新创建,则需要在Manifest中添加configChanges属性,在Activity中复写onConfigurationChanged方法。
①前台Activity —— 正在和用户交互的Activity,优先级最高。
②可见但非前台Activity —— 如Activity弹了一个对话框,导致Activity可见但位于后台,无法与用户直接交互。
③后台Activity —— 已经被暂停的Activity,比如执行了onStop,优先级最低。 当系统内存不足时,会按照优先级去杀死Activity,并通过onSaveInstanceState和onRestoreInstanceState来保存和恢复数据。
任务栈(Task):是一种用来放置Activity实例的容器,它是以栈的形式进行存放,当我们启动一个Application的时候,系统会为它默认创建一个对应的Task,用来放置根Activity。默认启动Activity会放在同一个Task中,新启动的Activity会被压入启动它的那个Activity的栈中,并且显示它。当用户按下回退键时,这个Activity就会被弹出栈,按下Home键回到桌面,再启动另一个应用,这时候之前那个Task就被移到后台,成为后台任务栈,而刚启动的那个Task就被调到前台,成为前台任务栈,Android系统显示的就是前台任务栈中的Top实例Activity。
作用: 由于Android强化了组件概念,弱化了Aplication的概念,所以在Android程序开发中,A应用的A组件想要使用拍照或录像的功能就可以不用去针对Camera类进行开发,直接调用系统自带的摄像头应用(称其B应用)中的组件(称其B组件)就可以了,但是这就引发了一个新问题,A组件运行在A应用中,B组件运行在B应用中,自然都不在同一个进程中,那么从B组件中返回的时候,如何实现正确返回到A组件呢?Task就是来负责实现这个功能的,它是从用户角度来理解应用而建立的一个抽象概念。
standard(标准模式) singleTop(栈顶复用) singleTask(栈内复用) singleInstance(单实例模式)
standard(标准模式):每次启动一个Activity都会重新创建一个新的实例。 当用ApplicationContext去启动standard模式的Activity时,会报如下错误。
这是因为standard模式的Activity默认会进入启动它的Activity所属的任务栈中,但是由于非Activity类型的Context(如ApplicationContext)并没有任务栈。 解决方法就是为Intent添加FLAG_ACTIVITY_NEW_TASK标记,这样启动的时候就会创建一个新的任务栈,相当于singleTask模式。 以standard方式启动的Activity被跨进程调用,在5.0之前新启动的Activity实例会放入发送Intent的Task的栈的顶部,尽管它们属于不同的程序,在5.0之后,上述情景会创建一个新的Task,新启动的Activity就会放入刚创建的Task中。
singleTop(栈顶复用):如果新Activity已经位于任务栈的栈顶,那么Activity不会被重新创建,同时它的onNewIntent方法会被调用。如果新Activity不在栈顶,那么新Activity仍会被重新创建。 应用场景:在通知栏点击收到的通知,然后需要启动一个Activity,这个Activity就可以用singleTop,否则每次点击都会新建一个Activity。
singleTask(栈内复用):当一个具有singleTask模式的Activity被启动后,比如Activity A,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例并放入到栈中。如果存在A所需的任务栈,并且存在A的实例,那么系统就会回调A的onNewIntent方法。singleTask具有ClearTop效果,会将位于它以上的Activity实例全部清除出栈。 TaskAffinity属性可以为Activity指定一个任务栈,属性值不能和包名相同,否则就相当于没有指定,因为默认情况下,所有的Activity的任务栈为应用的包名。 当TaskAffinity和singleTask配对使用的时候,待启动的Activity会运行在名字和TaskAffinity形同的任务栈中。
singleInstance(单实例模式):整个手机系统只有一个实例存在,不同的应用去打开这个activity 共享公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。应用场景:呼叫来电界面。这种模式的使用情况比较罕见,在Launcher中可能使用。
有两种方式为Activity指定启动模式:
1、通过AndroidMenifest
2、通过Intent设置标识来启动。
第二种的优先级高于第一种,当两种方式同时存在时,以第二种方式为准。
FLAG_ACTIVITY_NEW_TASK:指定singleTask启动模式。
FLAG_ACTIVITY_SINGLE_TOP:指定singleTop启动模式。
FLAG_ACTIVITY_CLEAR_TOP:当Activity启动时,在统一任务栈中所有位于它上面的Activity都要出栈。一般和FLAG_ACTIVITY_NEW_TASK配合使用,在这种情况下,如果被启动的Activity实例已经存在,系统就会回调onNewIntent方法;如果被启动的Activity采用的时standard模式,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。
Activit的启动模式分为显示调用和隐式调用,如果两者同时出现以显示调用为主。
action匹配规则:
Intent中的action必须能够和过滤规则中的action完全匹配(action的字符串值完全一样)。一个过滤规则中可以有多个action,只要Intent中的action存在且必须和过滤规则中的其中一个action相同。
category匹配规则:
Intent中如果携带category,那么所有的category都必须和过滤规则中的其中一个相同。 如果不设置category,那么系统在调用startActivity或者startActivityForResult的时候就会默认为Intent加上"android.intent.category.DEFAULT",为了Activity能够接收隐士调用,就必须在intent-filter中指定"android.intent.category.DEFAULT"。
data匹配规则:
data的匹配规则和action类似,如果过滤规则中定义了data,那么Intent中必须也要定义可匹配的data。
①如果Intent中的mimeType属性为"image/*",这种情况下虽然没有指定URI,但却又默认值,URL的默认值为content和file,也就是说,虽然没有指定URI,但是Intent中的URI部分的schema必须为content或者file才能匹配。
②如果要为Intent指定完整的data,必须要调用setDataAndType方法,不能先调用setData再调用setType,因为这两个方法会彼此清除掉对方的值。
当我们通过隐士方式启动一个Activity的时候,可以通过PackageManager的resolveActivity方法或者Intent的resolveActivity方法来进行判断。PackageManager还提供了queryIntentActivities方法。
IntentService是一个基于Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。
IntentService最起码有两个好处:
① 不需要自己去new Thread。
② 不需要考虑在什么时候关闭该Service。
startService:
调用onCreate()->onStartCommand() bindService:调用onBind() stopService:没有调用onDestory() Service仍然在运行! unbindService:调用onUnbind()->onDestory() 此时Service关闭!
startService:
调用onCreate()->onStartCommand() bindService:调用onBind() unbindService:调用onUnbind() Service仍然在运行! stopService:调用onDestory() 此时Service才关闭!
若被停止的服务依然有ServiceConnection 与其绑定,则服务不能销毁,直至我们把所有ServiceConnection 解绑。
当所有ServiceConnection 解绑后,系统会自动销毁服务。不包括同时用startService()启动的情况。此时,我们不得不再调用一次stopService来销毁它。
静态注册:
静态注册的广播接收器即使app已经退出,主要有相应的广播发出,依然可以接收到(但此种描述自Android 3.1开始有可能不再成立)。 自Android3.1开始,系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。 由此,对于系统广播,由于是系统内部直接发出,无法更改此intent flag值,因此,3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。
动态注册:
当此Activity销毁时,动态注册的广播接收器将不再接收到相应的广播。
Android中的广播可以跨进程甚至跨App直接通信,且注册是exported对于有intent-filter的情况下默认值是true,由此将可能出现安全隐患如下:
其他App可能会针对性的发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收到广播并处理;
其他App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。
无论哪种情形,这些安全隐患都确实是存在的。由此,最常见的增加安全性的方案是:
对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;
在广播发送和接收时,都增加上相应的permission,用于权限验证;
发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。
App应用内广播(LocalBroadcast),广播的发送者和接收者都同属于一个App。 相比于全局广播,App应用内广播优势体现在:
①安全性更高。
②更加高效。