关于任务栈Task

栈的概念
栈(Stack)是一种常用的数据结构,栈只允许访问栈顶的元素,栈就像一个杯子,每次都只能取杯子顶上的东西,而对于栈就只能每次访问它的栈顶元素,从而可以达到保护栈顶元素以下的其他元素.”先进后出”或”后进先出”就是栈的一大特点,先进入栈的元素总是要等到后进入栈的元素出栈以后才能出栈.递归就是利用到了系统栈,暂时保存临时结果,对临时结果进行保护.
栈的基本操作:压栈、弹栈

任务栈
Task简单的说就是一组以栈的模式聚集在一起的Activity组件集合,类似于一个填充了Activity的容器,最先加入的Activity会处于容器最下面,最后加入的处于容器最上面,而从Task中取出Activity时是从最顶端先取出,最后取出的是最开始添加Activity,这就是后进先出模式,而Activity在Task中的顺序是可以控制的,在Activity跳转时用到Intent Flag可以设置新建activity的创建方式。

Activity的启动模式

Activity启动模式有四种,可以根据实际的需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。
设置Activity的启动模式,只需要在AndroidManifest.xml里对应的<activity>标签设置Android:launchMode属性。

standard
默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。
例如:若我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上。点back键会依照栈顺序依次退出。

singleTop
可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。

singleTask
只有一个实例。
如果在同一个应用程序中启动它,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。
如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity。
singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。
可以使用singleTask来退出整个应用。
将主Activity设为SingTask模式,然后在要退出的Activity中转到主Activity,然后重写主Activity的onNewIntent函数,并在函数中加上一句finish。

singleInstance
只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。

Intent中常用的Flag

Flag表示Intent的标志位,常用于Activity的场景中,它和Activity的启动模式有着密切的联系。
下面列举的是和Activity启动模式相关的Flag属性:

Intent.FLAG_ACTIVITY_NEW_TASK
系统会检查当前所有已创建的Task中是否有该要启动的Activity的Task,若有,则在该Task上创建Activity;若没有则新建具有该Activity属性的Task,并在该新建的Task上创建Activity。

FLAG_ACTIVITY_SINGLE_TOP
这个FLAG就相当于启动模式中的singletop
比如说原来栈中情况是ABCD,在D中启动D,栈中的情况还是ABCD

FLAG_ACTIVITY_CLEAR_TOP
这个FLAG就相当于启动模式中的SingleTask,这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。
比如:原来栈中的情况是ABCD,这个时候从D中跳转到B,这个时候栈中的情况就是AB了

FLAG_ACTIVITY_NO_HISTORY
这个标记顾名思义意思就是说,用这个FLAG启动的Activity,一旦【不可见】,他就不会存在于任务栈中。
比如,原来是ABC,这个时候在C中以这个FLAG启动D的 ,D再启动E,这个时候栈中情况为ABCE。

FLAG_ACTIVITY_BROUGHT_TO_FRONT
比方说我现在在A中启动B,启动时在A中的Intent加上这个标记,此时在B中再启动CD(正常启动CD),此时栈的情况是ABCD。
如果这个时候在D中再启动B,这个时候栈的情况是 ACDB。
特别注意的是,我上面说的网上人描述的这个FLAG,会很容易让人误解成这样,A,B,C,D都是标准加载,然后我在D中启动A,这个intent加上FLAG_ACTIVITY_BROUGHT_TO_FRONT  ,就会误认为变成B,C,D,A!!其实不是,这个时候应该是A,B,C,D,A.不信的人大家试试看。不过下面这个标记和这个标记就会让大家明白了!

FLAG_ACTIVITY_REORDER_TO_FRONT
就按在 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT 最后说的,如果在A,B,C,D正常启动的话,不管B有没有用FLAG_ACTIVITY_BROUGHT_TO_FRONT启动,此时在D中启动B的话,还是会变成A,C,D,B的。

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
这个也不知道具体怎么用,看文档有点象开辟新的Task,不过测试完,不像那么简单。

FLAG_ACTIVITY_NO_USER_ACTION
onUserLeaveHint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而要退到background时使用。
比如,在用户按下Home键(用户的choice),它将被调用。比如有电话进来(不属于用户的choice),它就不会被调用。
那么系统如何区分让当前activity退到background时使用是用户的choice?
它是根据促使当前activity退到background的那个新启动的Activity的Intent里是否有     FLAG_ACTIVITY_NO_USER_ACTION来确定的。
注意:通过调用finish()使该activity销毁时不会调用该函数

关于taskAffinity属性

清单文件中,activity 的属性android:allowTaskReparenting用于设定:Activity是否能够从启动它的任务栈中转移到另一个与启动它的任务栈有相同taskAffinity属性值的任务栈中,转移时机是在另一个任务栈被带到前台的时候。如果设置为true,则能够转移,如果设置了false,则这个Activity必须要保留在启动它的那个任务栈中。

实验
1、新建两个工程,App1和App2
App1和App2都设置android:taskAffinity="aaa.aaa"android:allowTaskReparenting="true"
先运行App1,然后点击home键,让App1运行在后台
再运行App2,会发现这时显示的是App1的mainActivity,并且长按home键,会发现运行过的程序只有App1。

2、紧接着又在此基础上做了另外一个实验
在App1上新建一个secondActivity,设置android:taskAffinity="aaa.bbb"android:allowTaskReparenting="true"
在mainActivity中startActivity时,设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK,注意,这里的flag属性必须为newtask。
然后运行App1,点击进入secondActivity,这时长按home键,会发现运行过的程序中有两个App1,并且一个显示的是mainActivity另一个显示的是secondActivity。
这时点击home键,让程序回到后台
然后运行App2,会发现这时显示的是App1的mainActivity,此时点击返回会直接返回home。
注意,虽然此时App1的mainActivity被finish了,但App1的secondActivity还在后台等着呢。
同样,长按home键,会发现运行过的程序只有App1的两个任务栈,并没有App2。

3、在此基础上堆App1再次修改
在App1上新建一个thirdActivity,设置属性android:taskAffinity="aaa.aaa"android:allowTaskReparenting="true"
并在secondActivity中startActivity时,设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK;
运行App1,点击进入secondActivity,再进入thirdActivity,此时长按home键,会发现运行过的程序中有两个App1,并且一个显示的是secondActivity另一个显示的是thirdActivity。
此时点击返回,会回到mainActivity,再点击返回,会回到secondActivity,再点击返回,回到home页面。

以上实验中,如果startActivity时不设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK,则若先启动的是App1,那么不管是App1中的Activity还是App2中的mainActivity,都是运行App1的一个任务栈中。

演示代码

public class FirstActivity extends ListActivity {
    private List<String> mData;//数据
    private ListAdapter mAdapter;//适配器
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Toast.makeText(this, "onCreate,任务栈id:" + getTaskId(), Toast.LENGTH_SHORT).show();
        mData = new ArrayList<String>(Arrays.asList("启动第一个Activity", "启动第二个Activity", "====这是第一个Activity,任务栈id:" + getTaskId()));
        mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mData);
        setListAdapter(mAdapter);
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
        case 0:
            startActivity(new Intent(this, FirstActivity.class));
            break;
        case 1:
            Intent intent = new Intent(this, SecondActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//在这里设置连个卵用都没有!必须在清单文件中设置android:launchMode属性!
            startActivity(intent);
            break;
        }
    }
    protected void onNewIntent(Intent intent) {
        Toast.makeText(this, "onNewIntent,任务栈id:" + getTaskId(), Toast.LENGTH_SHORT).show();
        super.onNewIntent(intent);//父类的此方法是空实现
    }

    // 利用时间差方法完成两次返回键退出,防止误操作。
    private long currentBackPressedTime = 0;
    /**退出间隔*/
    public static final int BACK_PRESSED_INTERVAL = 2000;
    @Override
    //重写onBackPressed()方法,父类默认实现方式为调用 finish()方法
    public void onBackPressed() {
        // 判断时间间隔
        if (System.currentTimeMillis() - currentBackPressedTime > BACK_PRESSED_INTERVAL) {
            currentBackPressedTime = System.currentTimeMillis();
            Toast.makeText(this, "再按一次返回键退出", Toast.LENGTH_SHORT).show();
        } else {
            finish();
        }
    }
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // 是否触发按键为back键,如果不是正常响应。onKeyDown的优先级比onBackPressed高
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            onBackPressed();
            return true;
        } else {
            return super.onKeyDown(keyCode, event);
        }
    }
}

public class SecondActivity extends ListActivity {
    private List<String> mData;//数据
    private ListAdapter mAdapter;//适配器
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Toast.makeText(this, "onCreate,任务栈id:" + getTaskId(), Toast.LENGTH_SHORT).show();
        mData = new ArrayList<String>(Arrays.asList("启动第一个Activity", "启动第二个Activity", "====这是第二个Activity,任务栈id:"+getTaskId()));
        mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mData);
        setListAdapter(mAdapter);
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
        case 0:
            startActivity(new Intent(this, FirstActivity.class));
            break;
        case 1:
            Intent intent = new Intent(this, SecondActivity.class);
            startActivity(intent);
            break;
        }
    }
    protected void onNewIntent(Intent intent) {
        Toast.makeText(this, "onNewIntent,任务栈id:" + getTaskId(), Toast.LENGTH_SHORT).show();
        super.onNewIntent(intent);//父类的此方法是空实现
    }
}

任务栈 启动模式 Flag taskAffinity的更多相关文章

  1. 任务栈 启动模式 Task Flag launchMode MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. Activity 启动模式 FLAG

    原文:https://blog.csdn.net/youhongyan/article/details/64151922 一.Activity启动模式的设置在AndroidManifest.xml文件 ...

  3. Activity的任务栈Task以及启动模式与Intent的Flag详解

    什么是任务栈(Task) 官方文档是这么解释的 任务是指在执行特定作业时与用户交互的一系列 Activity. 这些 Activity 按照各自的打开顺序排列在堆栈(即“返回栈”)中. 其实就是以栈的 ...

  4. Activity启动模式 及 Intent Flags 与 栈 的关联分析

     http://blog.csdn.net/vipzjyno1/article/details/25463457    Android启动模式Flags栈Task   目录(?)[+] 什么是栈 栈 ...

  5. android Activity的启动模式与flag的见解

    最近做一个安卓项目,想要实现的效果就是:当打开一个按钮的时候,启动了一个A功能,当用户返回到桌面再继续进去的时候,不过之前在哪个Activity,都会先跳转到A功能的那个界面,当用户点击返回的时候,再 ...

  6. 【转】Activity启动模式 及 Intent Flags 与 栈 的关联分析

    http://blog.csdn.net/vipzjyno1/article/details/25463457    在学习Android的过程中,Intent是我们最常用Android用于进程内或进 ...

  7. activity的启动模式和栈管理

     在学习Android的过程中,Intent是我们最常用Android用于进程内或进程间通信的机制,其底层的通信是以Binder机制实现的,在物理层则是通过共享内存的方式实现的.     Intent ...

  8. Activity四种启动模式与Flag及affinity属性详解

    Activity有四种加载模式:standard(默认).singleTop.singleTask.singleInstance standard:Activity的默认加载模式,即使某个Activi ...

  9. Android Activity 启动模式和任务栈

    在了解了基本的Activity的生命周期后,我们能够很好的在一个Activity上面做相关的业务.但是这是不够的,因为Android通过任务栈来保存整个APP的Activity,合理的调度任务栈才能够 ...

随机推荐

  1. 万圣节的糖果(Halloween Sweets)

    今天遇到codewars的一道题,这是链接,讲的是关于万圣节的一个题目,简单点说,就是9个包裹,一个天平,两次称的机会,怎么找出9个包裹中唯一一个较重的包裹. 像我这种年轻时候喜欢研究难题获得存在感的 ...

  2. HDAO

    dx11 hdao10.1 除了dx的sample竟然搜不到什么文档.... 估计去问别人也是让我继续看代码.. ---------------------------------------- 算法 ...

  3. linux下mysql5.5的安装

    #rpm –qa|grep –i mysql查看已安装的mysql版本 如果有已存在的mysql版本则删除 安装服务端和客户端,去Oracle官网下载: # rpm -ivh MySQL-serve ...

  4. 多平台Native库打入JAR包发布实战

    1.前言 在开发Java应用的过程中,经常会遇到需要使用C/C++等Native语言编译的动态库或静态库,在这些情况下往往需要将预先编译好的各平台库文件与JAR包一同发布,鉴于简洁的原则,我们可能会希 ...

  5. vs2015 制作安装包额外需要安装的软件VSI_bundle

    vs2015 制作安装包额外需要安装的软件VSI_bundle 下载地址:http://files.cnblogs.com/files/sdner/VSI_bundle.rar

  6. Python成长之路【第二篇】Python基础之数据类型

    阅读目录 简介 1 什么是数据? x=10,10是我们要存储的数据 2 为何数据要分不同的类型 数据是用来表示状态的,不同的状态就应该用不同的类型的数据去表示 3 数据类型 数字(整形,长整形,浮点型 ...

  7. 关于富文本编辑器ueditor(jsp版)上传文件到阿里云OSS的简单实例,适合新手

    关于富文本编辑器ueditor(jsp版)上传文件到阿里云OSS的简单实例,适合新手   本人菜鸟一枚,最近公司有需求要用到富文本编辑器,我选择的是百度的ueditor富文本编辑器,闲话不多说,进入正 ...

  8. ES6走一波 Iterator

    Iterator---> for ... of 循环 Generator函数原生具有 Iterator接口,所以可采用数组的形式解构赋值

  9. Oracle字段类型及存储(一)

    Oracle中2000个byte,并不是2000个字符的意思,1个字符在Oracle中可能是1个byte到4个byte不等,需看数据库字符集的设置了. 对GBK字符集而言,ASCII码中128个字符使 ...

  10. 搜索评价指标——NDCG

      ◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:https://www.cnblogs.com/by-dream/p/9403984.html 概念 NDCG,Normali ...