Android LaunchMode案例篇

首先感谢小伙伴的关注。然后祝愿广大的情侣们节日快乐!

在开发中有时会遇到这种场景,用户点击注冊。第一步,第二步,完毕注冊跳转到登录界面,不须要用户一步一步的返回到登录界面。这是怎么实现的呢?

案例:有四个界面 A。B,C。D 从A跳转到B。B跳转到C,C跳转到D,D完毕注冊跳转到A,点击返回键退出程序。详细过程来看下图:

这里提供了三种常见的解决方式。

方案一

1.清单文件(AndroidManifest.xml)文件设置A的启动模式

        <activity android:name=".A"
            android:launchMode="singleTask">

2.在D文件:

 startActivity(new Intent(D.this, A.class));

方案二

使用 Intent 标志。在D文件:

        Intent intent =new Intent(D.this, A.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
        finish();

方案三

方案三相对于前面两种方案略微麻烦一些。但更利于我们理解栈的原理。

1.新建ActivityManager类:

public class ActivityManager {

    private static Stack<Activity> mStack;
    private static ActivityManager mActivityManager;
    public static ActivityManager getActivityManager() {
        if (mActivityManager == null) {
            mActivityManager = new ActivityManager();
        }
        return mActivityManager;
    }
    //将当前Activity推入栈中
    public void pushActivity(Activity activity) {
        if (mStack == null) {
            mStack = new Stack<Activity>();
        }
        mStack.add(activity);
    }
    //退出栈顶Activity
    public void popActivity(Activity activity) {
        if (activity != null) {
            //在从自己定义集合中取出当前Activity时,也进行了Activity的关闭操作
            activity.finish();
            mStack.remove(activity);
            activity = null;
        }
    }
    //获得当前栈顶Activity
    public Activity currentActivity() {
        Activity activity = null;
        if (!mStack.empty())
            activity = mStack.lastElement();
        return activity;
    }
    //退出栈中 cls曾经的全部Activity
    public void popAllActivityExceptOne(Class cls) {
        while (true) {
            Activity activity = currentActivity();
            if (activity == null) {
                break;
            }
            if (activity.getClass().equals(cls)) {
                break;
            }
            popActivity(activity);
        }
    }
    //获取栈
    public Stack<Activity> getStackActivity() {
        if (mStack != null) {
            return mStack;
        }
        return new Stack<Activity>();
    }
}

2.MyApplication文件(记得在清单文件里声明)

public class MyApplication extends Application {

    public static ActivityManager activityManager = null;

    @Override
    public void onCreate() {
        super.onCreate();
        activityManager = ActivityManager.getActivityManager();
    }

    //获取实例
    public ActivityManager getActivityManager() {
        return activityManager;
    }
}

3.BaseActivity文件(公共Activity)

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ((MyApplication)getApplication()).getActivityManager().pushActivity(this);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
      ((MyApplication)getApplication()).getActivityManager().popActivity(this);
    }
}

4.D文件

 startActivity(new Intent(D.this, A.class));
        ((MyApplication) getApplication()).getActivityManager().popAllActivityExceptOne(A.class);

LaunchMode

launchMode 属性指明了 activity 启动 task 的方式。 launchMode 属性可设为四种启动模式:

  • standard
  • singleTop
  • singleTask
  • singleInstance

standard

默认值。系统在启动 activity 的 task 中创建一个新的 activity 实例。并把 intent 传送路径指向它。该 activity 能够被实例化多次,各个实例能够属于不同的 task,一个 task 中也能够存在多个实例。

singleTop

假设 activity 已经存在一个实例并位于当前 task 的栈顶,则系统会调用已有实例的onNewIntent()方法把 intent 传递给已有实例,而不是创建一个新的 activity 实例。activity 能够被实例化多次,各个实例能够属于不同的 task。一个 task 中能够存在多个实例(但仅当 back stack 顶的 activity 实例不是该 activity 的)。

比方。假定 task 的 back stack 中包括了根 activity A 和 activities B、C、D(顺序是 A-B-C-D;D 在栈顶)。

这时过来一个启动 D 的 intent。假设 D 的启动模式是默认的”standard”,则会启动一个新的实例。栈内容变为 A-B-C-D-D。

可是。假设 D 的启动模式是”singleTop”。则已有的 D 实例会通过onNewIntent():接收这个 intent,由于该实例位于栈顶——栈中内容仍然维持 A-B-C-D 不变。当然,假设 intent 是要启动 B 的。则 B 的一个新实例还是会增加栈中,即使 B 的启动模式是”singleTop”也是如此。

singleTask

系统将创建一个新的 task,并把 activity 实例作为根放入其中。可是,假设 activity 已经在其他 task 中存在实例,则系统会通过调用事实上例的onNewIntent() 方法把 intent 传给已有实例。而不是再创建一个新实例。 此 activity 同一时刻仅仅能存在一个实例。

也能够这么来理解, 假设 task 中不存在 activity 实例,则新建实例并压入栈顶;假设存在 activity 实例并位于栈顶,则复用。假设存在 activity 实例并不位于栈顶。则清空 task 中 activity 实例之上的元素。使 activity 实例位于栈顶。

singleInstance

除了系统不会把其他 activity 放入当前实例所在的 task 之外,其他均与”singleTask”同样。activity 总是它所在 task 的唯一成员;它所启动的不论什么 activity 都会放入其他 task 中。

举个样例:假定 task 的 back stack 中包括了根 activity A 和 activities B、C、D(顺序是 A-B-C-D;D 在栈顶),而且 activities B 的启动默认设置为 singleInstance 。那么他们的出栈顺序为 D-C-A-B 。

Intent几种常见的flags

  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP

注意:假设 activity 同一时候设置了 launchMode 和 flags ,那么 flags 优先级大于 launchMode 。

我们这里须要先来了解一下 属性中的 taskAffinity:

taskAffinity

affinity 表示 activity 预期所处的 task 。 缺省情况下。同一个应用中的全部 activity 都拥有同一个 affinity 值。

因此,同一个应用中的全部 activity 默认都期望位于同一个 task 中。 只是。你能够改动 activity 默认的 affinity 值。 不同应用中的 activity 能够共享同一个 affinity 值。同一个应用中的 activity 也能够赋予不同的 task affinity 值。

你能够用 元素的 taskAffinity 属性改动 activity 的 affinity,taskAffinity 属性是一个字符串值。必须与 元素定义的包名称保证唯一性,由于系统把这个包名称用于标识应用的默认 task affinity 值。

  1. 依据affinity又一次为 activity 选择宿主task(与allowTaskReparenting属性配合工作)。
  2. 启动一个 activity 过程中 Intent 使用了 FLAG_ACTIVITY_NEW_TASK 标记,依据 affinity 查找或创建一个新的具有相应affinity的task。

默认情况下。一个应用内的全部 activity 都具有同样的 affinity,都是从 application 继承而来,而 application 默认的 affinity 是 manifest 文件里的包名。

我们也能够在 manifest 文件设置 taskAffinity 属性值:

    package="com.github.ws.launchmodedemo">

    <application
        android:taskAffinity="com.grasp.demo"

也能够单独为某个 activity 设置 taskAffinity 属性值。

FLAG_ACTIVITY_NEW_TASK

当Intent对象包括这个标记时,系统会寻找或创建一个新的 task 来放置目标 activity 。寻找时依据目标 activity 的taskAffinity 属性进行匹配,假设找到一个 task 的 taskAffinity 与之同样,就将目标 activity 压入此 task 中。假设查找无果,则创建一个新的 task,并将该 task 的 taskaffinity 设置为目标 activity 的 taskactivity。将目标 activity 放置于此 task。注意,假设同一个应用中 activity 的 taskaffinity 都使用默认值或都设置同样值时。应用内的 activity 之间的跳转使用这个标记是没有意义的,由于当前应用 task 就是目标 activity 最好的宿主。我们来看看以下的这个样例:

录制工具不是非常清晰,有些模糊了。

从上图其中非常明显的看出。程序A中有(a。b界面)。程序B中也有(a。b界面)。在程序A的b界面跳转到程序B的b界面:

        Intent intent=new Intent("com.github.ws.flagdemo.B");
        startActivity(intent);

按Home键回到主屏。在主选单中启动程序B;按Home键回到主屏,在主选单中启动程序A。

我们发如今从程序A跳转到程序B的b之后,b实例好像是嵌入到了程序A中,可是不影响程序B的正常执行。

然后我们改动一下跳转的代码:

  Intent intent=new Intent("com.github.ws.flagdemo.B");
  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  startActivity(intent);

我们看到区别了吧。当我们再次启动程序B时,并没有显示程序B的a界面,而是显示了b界面,当我们程序B返回到a界面,再次打开程序A,显示的是A的b界面。

由此可见, FLAG_ACTIVITY_NEW_TASK应该这样去理解:依据 activity affinity 推断是否须要创建新的Task,然后再创建新的Activity实例放进去。

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_CLEAR_TOP表示启动的 activity 会将 task 中位于其上的 activity 都强制出栈。使其自身位于栈顶。与Activity启动模式中的 singleTask 同样。

FLAG_ACTIVITY_SINGLE_TOP

当task中存在目标Activity实例而且位于栈的顶端时,不再创建一个新的,直接利用这个实例。与Activity启动模式中的singleTop效果同样。

由于篇幅原因。文章到这里就结束了。希望看了上文,对你有所帮助。

时间: 2024-10-12 12:36:06

Android LaunchMode案例篇的相关文章

android launchMode理解以及应用场景

在我们写应用的时候,常常涉及多个activity组件之间的跳转.比如说某个资讯的页面中,点击下一篇资讯跳转相同的页面,只有页面的数据不一样.一般情况下我不会注意launchMode 这个属性,只会使用默认的,这样会产生大量重复的activity.那是因为之前不了解,所以特此研究学习. 1.如何指定launchMode 基本上我们可以直接指定一个launchMode属性在AndroidManifest.xml 文件中 <activity android:name=".views.MainAc

Android中插件开发篇之----动态加载Activity(免安装运行程序)

一.前言 又到周末了,时间过的很快,今天我们来看一下Android中插件开发篇的最后一篇文章的内容:动态加载Activity(免安装运行程序),在上一篇文章中说道了,如何动态加载资源(应用换肤原理解析),没看过的同学,可以转战: http://blog.csdn.NET/jiangwei0910410003/article/details/47679843 当然,今天说道的内容还这这篇文章有关系.关于动态加载Activity的内容,网上也是有很多文章介绍了.但是他们可能大部分都是介绍通过代理的方

Android launchMode 笔记---taskAffinity属性和Intent标记体会

launchmode的四种模式,不需要细说:standard.singleTop.singleTask.singleInstance. 此博客关注的是,关于Activity中关于Affinity(亲和力)&Intent标记的东西,即使是Android老鸟,也不一定将其中的细节理解透彻. 使用Intent启动一个Activity,有如下标记: 1.FLAG_ACTIVITY_NEW_TASK 2.FLAG_ACTIVITY_CLEAR_TOP 3.FLAG_ACTIVITY_RESET_TASK_

Android NDK开发篇(五):Java与原生代码通信(数据操作)

尽管说使用NDK能够提高Android程序的运行效率,可是调用起来还是略微有点麻烦.NDK能够直接使用Java的原生数据类型,而引用类型,由于Java的引用类型的实如今NDK被屏蔽了,所以在NDK使用Java的引用类型则要做对应的处理. 一.对引用数据类型的操作 尽管Java的引用类型的实如今NDK被屏蔽了,JNI还是提供了一组API,通过JNIEnv接口指针提供原生方法改动和使用Java的引用类型. 1.字符串操作 JNI把Java的字符串当作引用来处理,在NDK中使用Java的字符串,须要相

android控件篇:ViewPager+Fragment+GridView的使用(与AndroidQuery框架结合)

最近看了一个AndroidQuery的框架,里面的Demo,有个界面,让博主很喜欢.左右滑动十分顺畅,手感很好,于是拿来和大家分享一下.先看一下效果图: 从图中可以看出,上面的布局是一个Layout里面嵌套有个ViewPager,ViewPager中包含着Fragment,Fragment的布局文件包含了一个简单的GridView,GridView的Item布局很简单,就是一个100*100大小的图片.好啦,先说这么多,然后咱们看代码吧. 最外层Activity的布局文件 <?xml versi

比你想象中还要强大的枚举类型---案例篇

前几天写了一篇介绍枚举功能强大的文章.有几个朋友给我指正说,没有案例单纯描述不够直观.确实啊,在这里我就在写一个案例篇,对上次的文章做补充说明. 此案例是一个游戏服务器的消息识别器的简化.做过游戏开发都知道,客户端和服务器之间的交互需要定义很多的消息类型,而且这个消息类型是需要不断扩展的.消息识别器就是根据客户端发送过来的消息编码封装成消息实体对象,以供业务逻辑层处理.这里就用这个简化后的消息识别器展示一下枚举的一个应用.(此处主要用作枚举的一个应用实例演示,由于代码做了简化处理,设计上难免会有

PM撸代码之Android【武侠篇:封装、继承、多态】

80 PM撸代码之Android[武侠篇:封装.继承.多态] 这是Android系列的第六篇文章,在之前的一篇文章中,已经了解了面向对象的基础概念,这一篇将会通过武侠江湖的类比,讲解面向对象的更多内容,感谢小伙伴们一直以来的支持. 武林门派的三个特征 1 独门秘籍(封装) 2 传承的门派(继承) 3 看情况使功夫和换个姿势说明问题(多态) [封装] 1 门派独门秘籍(封装) 前一篇已经说到,当达摩上了嵩山以后,江湖就正式进入门派时代.每个门派区别于其他门派,肯定是因为这个门派拥有独门武功秘籍.举

Android开发经典书籍下载——《Android 4高级编程》《疯狂Android讲义》《Android应用开发详解(郭宏志)》《Android应用案例开发大全》《Android 3D游戏开发技术》

这是我收集的关于android开发方面的经典书籍,高清PDF电子版,可以在我的百度网盘免费下载,希望对需要的朋友有帮助. 目录: <Android 4高级编程>(附完整源代码) <疯狂Android讲义> <Android应用开发详解(郭宏志)> <Android应用案例开发大全> <Android 3D游戏开发技术> <Android内核剖析 柯元旦> <深入理解Android  卷1> <深入理解Android

Android提高21篇之一:MediaPlayer

本文介绍MediaPlayer的使用.MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用MediaPlayer,要视情况选择了.MediaPlayer播放音频比较简单,但是要播放视频就需要SurfaceView.SurfaceView比普通的自定义View更有绘图上的优势,它支持完全的OpenGL ES库. 先贴出本文程序运行结果的截图,上面是播放/停止音频,可用SeekBar来调进度,下面