singleTask和singleInstance区别辨析

上次对lauchMode进行了全面的研究(http://www.cnblogs.com/webor2006/p/3979623.html),其中提到了待研究的东西,就是关于singleTask和singleInstance之间的差别,这里就开始一点点找寻答案。

实际上关于这个网上已经有牛人给出解释了,http://blog.csdn.net/wang_zun_ren/article/details/6823257

下面用实验来验证下,最终来进行总结,依然拿来主义,"拿来不可耻,可耻的是技术不研究透":

现有2个项目,taskA、taskB。taskA负责调用taskB中指定的界面。

taskB中有3个界面,a、b、c,每个界面显示它所在的task id。

ActivityA.java:

public class ActivityA extends Activity implements OnClickListener {

    private Button button;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("cexo", "ActivityA onCreate()----taskId:" + getTaskId());
        setContentView(R.layout.activity_a);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Intent intent = new Intent(this, ActivityB.class);
        startActivity(intent);
    }
}

ActivityB.java:

public class ActivityB extends Activity implements OnClickListener {
    private Button button;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("cexo", "ActivityB onCreate()----taskId:" + getTaskId());
        setContentView(R.layout.activity_b);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d("cexo", "ActivityB onNewIntent()----taskId:" + getTaskId());
    }

    @Override
    public void onClick(View view) {
        Intent intent = new Intent(this, ActivityC.class);
        startActivity(intent);
    }
}

ActivityC.java:

public class ActivityC extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("cexo", "ActivityC onCreate()----taskId:" + getTaskId());
        setContentView(R.layout.activity_c);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d("cexo", "ActivityC onNewIntent()");
    }

}

 

其中taskA就是简单调用taskB中的ActivityB,代码如下:

 

MainActivity.java:

 

public class MainActivity extends Activity implements OnClickListener {

    private Button button;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("cexo", "taskA onCreate()----taskId:" + getTaskId());
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        startActivity(new Intent("com.testb.launchmodeltest.ActivityB"));//跳转到taskB中的ActivityB界面
    }
}

 

 

下面会设计一些实验来进行对比,分别在场景一样的情况下将ActivityB的lauchMode分别设置为singleTask和singleInstance做对比,会参考博客,但会更加细化,从这些实验中,最后来总结出两者的区别,下面开始:

实验一:"先运行taskB工程,按如下顺序打开页面:ActivityA---->ActivityB---->ActivityC,来观察栈情况~"

singleTask,运行如下:

可以发现三个界面都处于同一个Task中。

singleInstance:

其中ActivityB新开了一个Task,从这个实验可以发现:

singleTask并非一定是单独成栈的,但是singleInstance一定是单独成栈的

实验二:"此时按Home键回到桌面,再切回到前台,来看下退栈的顺序"

singleTask:

其退栈过程是按先进后出的顺序:ActivityC---->ActivityB---->ActivityA,因为这三个是在同一个栈中。

singleInstance:

由于ActivityB在新的栈里,而当前ActivityC所在栈在最前面,所以先退ActivityC所在栈,其中ActivityA跟它同一栈,但是退完了当前栈之后就没了。在新栈中的ActivityC就木见了,这个需要注意!
实验三:"在实验一中可以发现singleTask的并没有新开一个栈,那如果用taskA去调用taskB的lauchMode为singleTask的ActiviyB界面呢?【在taskB工程之前没有打开过ActivityB界面】"

从这个实验中可以总结:“singleTask在同一个进程里,是不会新建Task的,只有跟打开它的在不同进程,打开该界面时才会单独成栈”

实验四:"在实验三的基础上,在taskB界面上,继续点击跳转到ActivityC界面,然后再看一下退栈的顺序"

从实验结果来看,新打开的ActivityC跟ActivityB在同一个进程,也在同一个栈,其退栈时是先退当前栈,然后再退其它栈。

如果在正式退栈之前,进行一个操作,就是按home键,看是否跟实验二中的singleInstance退栈一样,在退完当前栈之后回不到单独成栈的ActivityB界面了:

从中可以发现,切至home之后,singleTask的ActivityB走了onNewIntent(),并且ActivityC被干掉了,回退一次就退出了,并没有回到taskA,可见当切home之后,其退栈过程并非是先退当前栈,再退其它栈了。那taskA程序在按home键之后,就不受栈管理了,要想回到taskA,则需要点击一下该APP既可,如下:

从实验结果来看,只有选择了这个APP,才会回到相对应的界面,当回退完这个APP之后,就不会回退到其它APP了。

而从作者的总结中也可以体会到:"这说明,SingleTask所标注的Activity在被自身的app调用时,是不新建task的,同时,如果系统中存在了这个SingleTask界面的实例时,会将其所在的task切换到前台,并把SingleTask界面之后开启的其他界面全部关闭(有待考证是否关闭)。"

那如果ActivityB是singleInstance时,同样的操作步骤,在不按home,其结果还是一样么?

从中可以发现ActivityC跟ActivityB不在同一个栈,分别新开了不同的栈,回退时,很退当前栈再退其它栈,确实是的。

同样这时在正式退栈之前,进行一个操作,就是按home键,看结果会是怎样:

从中可以发现,跟singleTask不同的地方,就是直接回到了ActivityC界面,再按一次Back键,就直接退出了,ActivityB就不见了,同样如果要回到taskA所在界面,切在home中选择该进程既可,跟singleTask情况一样。

实验五:"继续基于实验四中最后一个步骤,singleInstance时,切换home界面后,再切回界面时,退一次ActivityC之后就退出桌面了,这时ActivityB就不见了,基于这种场景,再次打开taskB走一遍流程"

从中可以发现,再次打开ActivityB时,走的是onNewIntent(),这说明之前消失的ActivityB所在的Task还存在,再打开时则直接切到前台上来了,这个在http://www.cnblogs.com/webor2006/p/3979623.html也有论证,这也是singleInstance的一个特点。

实验五:验证作者的实验:"a界面被调用,这时按Home键返回到桌面,启动taskA,并调用b界面,这时b界面的taskid与a界面的一致,说明b界面与a界面同属于一个task。如果直接运行taskA调用b界面,b的taskid与taskA的界面的taskid不同,说明在新task中实例化了b界面,由b界面调用c界面,c界面的taskid与b界面一致,说明b与c同属于一个task。"

第一步:启动taskB,调用ActivityA界面

第二步:按home键切换到桌面

第三步:启动taskA,调用taskB中的ActivityB界面,观看此时的ActivityB是否是在新的栈中【从下面实验来看,是在新的栈中,而且跟先前打开的ActivityA在同一个栈】

第四步:再由ActivityB调起ActivityC界面,观察ActivityC跟ActivityB是否在同一个栈中【从下面实验来看,是在同一个栈中,所以可以说明如果是被其它APP调用起来的,它所在栈就是自身APP所在栈】

依照上面的步骤,下面来看下实验结果:

总结:

1、SingleTask所标注的Activity在被自身的app调用时,是不新建task的,而如果是被其它APP调用起来的,它所在栈就是自身APP所在栈;而SingleInstance所标注的Activity在被自身的app调用时,一定会新建task的,前提是该Activity没有被打开过,而如果是被其它APP调用起来的,它所在栈不是自身APP所在栈。

2、如果系统中存在了这个SingleTask界面的实例时,会将其所在的task切换到前台,同样SingleInstance也一样;并把SingleTask界面之后开启的其他界面会全部销毁掉,而SingleInstance是不会的。

3、在按home切回桌面,再切回该APP时,如果app中task中有为singleTask的Activity,它之上的Activity都会被清掉,而如果里面有singleInstance的Activity,而它不是当前界面,则它就无法显示了,但是它所在的task还存在,如果之后再调起这个界面则会起该Activity的onNewIntent()方法。

posted on 2014-11-06 18:05  cexo  阅读(3603)  评论(0)    收藏  举报

导航