任务栈 启动模式 Flag taskAffinity


关于任务栈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_1mData);
        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_1mData);
        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);//父类的此方法是空实现
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值