与界面跳转联系比较紧密的概念是Task(任务)和Back Stack(回退栈),activity的启动模式会影响Task和Back Stack的状态,Intent类中定义的一些标志(以FLAG_ACTIVITY_开头)和activity的属性taskAffinity也影响Task和Back Stack的状态。Task是一个存在于Framework层的概念,在android中,一个应用就是一组组件的集合android组件化程度极高,application是由四大组件组成的。在app安装时,系统会读取manifest的信息,将所有的组件解析出来,以便在运行时对组件进行实例化和调度。task是在程序运行时,只针对activity的概念,task是一组相互关联的activity的集合,它是存在于framework层的一个概念,控制界面的跳转和返回。这个task存在于一个称为back
stack的数据结构中,也就是说,framework是以栈的形式管理用户开启的activity。这个栈的基本行为是,当用户在多个activity之间跳转时,执行压栈操作,当用户按返回键时,执行出栈操作。task是可以跨应用的,这正是task存在的一个重要原因。有的Activity,虽然不在同一个app中,但为了保持用户操作的连贯性,把他们放在同一个任务中,进程是操作系统内核中的一个概念,表示直接受内核调度的执行单位。java编写的应用程序,运行在dalvik虚拟机中,可以认为一个运行中的dalvik虚拟机实例占有一个进程,在默认情况下,一个应用程序的所有组件运行在同一个进程中,应用程序中的不同组件也可以运行在不同的进程中。只需要在manifest中用process属性指定组件所运行的进程的名字。如下所示:
<activity android:name=".MyActivity" android:label="@string/app_nam" android:process=":remote"> </activity>
adb shell dumpsys activity )其实,把启动模式设置为singleTask,framework在启动该activity时只会把它标示为可在一个新任务中启动,至于是否在一个新任务中启动,还要受其他条件的限制。增加一个taskAffinity属性给启动的singleTask的aty,那么将在新task启动。
case RESULT_CANCELED: 然后再进入B的onCreate,也不会得到返回值,所以这里只能理解是协议规范了记住singletask的activity不要用startactivityforresult就好,但是能启动在一个task,只是无法传值。
case RESULT_CANCELED:也就能理解了。具体参照博文Sodino。
taskAffinity表示一个任务,这个任务就是当前activity所在的任务。The task that the activity has an affinity
for在概念上,具有相同的affinity的activity(即设置了相同taskAffinity属性的activity)属于同一个任务。一个任务的affinity取决于这个任务的根activity(root
activity)的taskAffinity。默认情况下,一个应用中的所有activity具有相同的taskAffinity,即应用程序的包名。我们可以通过设置不同的taskAffinity属性给应用中的activity分组,也可以把不同的应用中的activity的taskAffinity设置成相同的值。为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task。taskAffinity可以影响当activity以FLAG_ACTIVITY_NEW_TASK标志启动时,它会被启动到哪个任务中。这句话的意思是,当新启动的activity(SecondActivity)是以FLAG_ACTIVITY_NEW_TASK标志启动时(可以认为FLAG_ACTIVITY_NEW_TASK和singleTask作用相同,当启动模式为singleTask时,framework会将它的启动标志设为FLAG_ACTIVITY_NEW_TASK),framework会检索是否已经存在了一个affinity为SecondActivity的taskAffinity.second的任务(即一个TaskRecord对象),而不是随便新建task,有和SecondActivity的taskAffinity时就不新建task了,只是去那个和自己属性一样的task,如果当前的task就是和自己属性相同那就是在当前task了,官方文档可能就是这意思,寻觅和自己属性相同的“新”task。1、如果存在这样的一个任务,则检查在这个任务中是否已经有了一个SecondActivity的实例,如果已经存在一个SecondActivity的实例,重用这个任务和任务中的SecondActivity实例,将这个任务调到前台,清除位于SecondActivity上面的所有Activity,显示SecondActivity,并调用SecondActivity的onNewIntent();如果不存在一个SecondActivity的实例,会在这个任务中创建SecondActivity的实例,并调用onCreate()方法。2、
如果不存在这样的一个任务,会创建一个新的affinity为com.jg.zhang.androidtasktest.second的任务,并且将SecondActivity启动到这个新的任务中。。。SecondActivity只设置启动模式为singleTask,而不设置taskAffinity,即和启动他的Activity的taskAffinity相同,都为应用的包名,那么SecondActivity是不会开启一个新任务的,这就是著名的怪现象(文档表述不清造成)。
app的A aty 启动B aty ,home。Y app的C aty启动D aty时,B和D是一样的taskAffinity,那么B和D会在一个task但是AB一个进程CD一个进程。
设置singleTask模式只意味着“可以在一个新的任务中开启”,至于是不是真的会在新任务中开启,在framework中还有其他条件的限制。由上面的介绍可知,这个条件为:是否已经存在了一个由他的taskAffinity属性指定的任务。
在启动一个singleTask的Activity实例时,如果系统中已经存在这样一个实例,就会将这个实例调度到任务栈的栈顶,并清除它当前所在任务中位于它上面的所有的activity。此时不走oncreate,走onNewIntent()。
以singleInstance模式启动的Activity具有全局唯一性,即整个系统(整个系统所有的app中只有一个)中只会存在一个这样的实例,具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中,被singleInstance模式的Activity开启的其他activity,能够开启一个新任务,但不一定开启新的任务,也可能在已有的一个任务中开启。
Framework既能在同一个任务中对Activity进行调度,也能以Task为单位进行整体调度。在启动模式为standard或singleTop时,一般是在同一个任务中对Activity进行调度,而在启动模式为singleTask或singleInstance是,一般会对Task进行整体调度。
onNewIntent()非常好用,Activity第一启动的时候执行onCreate()---->onStart()---->onResume()等后续生命周期函数,也就时说第一次启动Activity并不会执行到onNewIntent(). 而后面如果再有想启动Activity的时候,那就是执行onNewIntent()---->onResart()------>onStart()----->onResume().
如果android系统由于内存不足把已存在Activity释放掉了,那么再次调用的时候会重新启动Activity即执行onCreate()---->onStart()---->onResume()等。 当调用到onNewIntent(intent)的时候,需要在onNewIntent()
中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getIntent()都是得到老的Intent。