Android常见的Activity启动模式(LaunchMode)和使用场景

一、为什么需要启动模式

在Android开发中,我们都知道,在默认的情况下,如果我们启动的是同一个Activity的话,系统会创建多个实例并把它们一一放入任务栈中。当我们点击返回(back)键,这些Activity实例又将从任务栈中一一移除,遵循的原则是“后进先出”(先进后出)。

这里我们考虑一个问题,当我们多次启动同一个Activity,系统也会创建多个实例放入任务栈中,这样岂不是很耗费内存资源?为了解决这一问题,Android为Actiivty提供了启动模式。

Activity的启动模式有四种:standard、singleTop、singleTask和singleInstance。

二,启动模式分类

1. standard:标准模式

这种启动模式为标准模式,也是默认模式。每当我们启动一个Activity,系统就会相应的创建一个实例,不管这个实例是否已经存在。这种模式,一个栈中可以有多个实例,每个实例也都有自己的任务栈。而且是谁启动了此Activity,那么这个Activity就运行在启动它的Activity所在的栈中。

 
5777390-a8b256a1bcfadde2.png
 

 

 
5777390-43ce4ca031748a56.png
 

第一次跳转

 

 
5777390-b7da94fcc4fa8183.png
 

第二次跳转

 

 
5777390-eb632e19cabe624f.png
 

从结果可以看出,每一次都会重新创建新的实例,当选择返回键,会逐层按照先进后出的顺序将activity推出栈

2、singleTop:栈顶复用模式

这种启动模式下,如果要启动的Activity已经处于栈的顶部,那么此时系统不会创建新的实例,而是直接打开此页面,同时它的onNewIntent()方法会被执行,我们可以通过Intent进行传值,而且它的onCreate(),onStart()方法不会被调用,因为它并没有发生任何变化。但是如果没有在栈顶,那么依然会再次创建新的实例,这样就会出现重复页面存在的问题。

 

 
5777390-51b1c2d7c195bc70.png
 
 
5777390-3b84cff5c608f2a8.png
 
 
5777390-027cc23a1a0e516a.png
 

 

 
5777390-cffe6c4938a00feb.png
 

 

 
5777390-78cdba65ee1bf262.png
 

 

下面演示的是如果没有在栈顶,即中间跳转到了其他的页面,然后再跳转都自身,会发现系统重新初始化了实例,而不再是简单读取展示了

 
5777390-0de7eaf1f98d0464.png
 

 

 
5777390-64274e0693bda78c.png
 

 

 
5777390-48c0be172de527c2.png
 

 

 
5777390-4ee92d10543164e1.png
 

使用场景:

这种模式应用场景的话,假如一个新闻客户端,在通知栏收到了3条推送,点击每一条推送会打开新闻的详情页,如果为默认的启动模式的话,点击一次打开一个页面,会打开三个详情页,这肯定是不合理的。如果启动模式设置为singleTop,当点击第一条推送后,新闻详情页已经处于栈顶,当我们第二条和第三条推送的时候,只需要通过Intent传入相应的内容即可,并不会重新打开新的页面,这样就可以避免重复打开页面了

3、singleTask:站内复用模式

在这个模式下,如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈,因为singleTask本身自带clearTop这种功能。并且会回调该实例的onNewIntent()方法。其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。不设置taskAffinity属性的话,默认为应用的包名。

在复用的时候,首先会根据taskAffinity去找对应的任务栈:

1、如果不存在指定的任务栈,系统会新建对应的任务栈,并新建Activity实例压入栈中。

2、如果存在指定的任务栈,则会查找该任务栈中是否存在该Activity实例

      a、如果不存在该实例,则会在该任务栈中新建Activity实例。

      b、如果存在该实例,则会直接引用,并且回调该实例的onNewIntent()方法。并且任务栈中该实例之上的Activity会被全部销毁。

使用场景:

SingleTask这种启动模式最常使用的就是一个APP的首页,因为一般为一个APP的第一个页面,且长时间保留在栈中,所以最适合设置singleTask启动模式来复用。

 

 
5777390-ccf7824ed9894ac8.png
 

4、singleInstance:单实例模式

单实例模式,顾名思义,只有一个实例。该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。也就是创建了单独的任务栈,当多个不同的任务栈存在时,选择返回键,就会直接回到上一个任务栈而且展示上一个任务栈顶部的页面,但是顶部页面之前的其他页面再次选择返回键是无法展示的。

启动该模式Activity的时候,会查找系统中是否存在:

1、不存在,首先会新建一个任务栈,其次创建该Activity实例。

2、存在,则会直接引用该实例,并且回调onNewIntent()方法。

特殊情况:该任务栈或该实例被销毁,系统会重新创建。

使用场景:

很常见的是,电话拨号盘页面,通过自己的应用或者其他应用打开拨打电话页面 ,只要系统的栈中存在该实例,那么就会直接调用。

实际开发中出现的问题 (下面的解说请自行忽略,发现在系统5.0以下是有问题的,无法达到目的,系统7.0下是好的。最后还是使用比较笨拙的方式实现了兼容,在文章底部有具体实现)

那么项目想做如下的实现:

支持自动登录,如果用户是第一次登录,就展示登录页面,如果登录成功,下一次杀掉进程后直接进入主页面,而不再展示登录页面。除非用户选择了登出,才会再次回到登录页面。大致的交互流程如下:

 
5777390-516830615449029b.png
图一
 
5777390-b7b7b3b61462e286.png
图二

 

 
5777390-6175ee260327e4bc.png
图三

第一次登录:图一 ->登录成功 ->图二->图三选择登出->回到图一登录页

已经登录成功:图二->图三选择登出->回到图一登录页

页面结构实现思路

mainActivity 作为主页面,判断是否是第一次登录,如果是第一次登录就加载loginactivity,如果已经登录成功就加载主页面。那么这一过程中本来想设计的思路是这样的:

mainActivity 设置为singleTask类型,login和主页面都设置为singletask类型的,其他的默认是Standard类型的。这样设计的初衷是各个独立的主要页面保证只有一个存在,在用户选择登出的时候就可以将堆栈中mainactivity之上的所有activity都销毁掉了,但是事实证明上来就出现了问题。

问题表现 1登录页面输入有效的地址等信息,此时选择home键,然后再次resume到前台,内容被清空了。结果又想换成singleinstance试试,一样不行。最后发现应用程序的main页面如果设置为这两种类型的,选择home键,系统就会调用destroy方法,将top页面销毁掉。

解决办法1: 最后只能修改成singleTop类型的。

问题表现2:上面home键的问题解决了,但是新的问题出现了,最简单的表现就是在login页面选择back按钮,竟然出现了空白页,这个空白页其实就是mainactivity,因为设置为了singletop,因此当其在栈顶,系统会又一次复用。

解决办法2: 想办法在login页面选择back键同时销毁掉mainactivity。因此在mainactivity启动login和主页面的时候都使用了方法startActivityForResult,这样在返回到mainactivity的时候就能接收到回调消息并且将自己finish掉。但是这里可以看到resultcode==4,这个是在login成功后也会返回到这里,不能简单finish mainactivity,要继续调用方法进入到主页面

 
5777390-628cacdb274cb815.png
 

问题表现3: 当用户登录成功后,杀掉进程,再次启动app,此时其实loginactivity是没有被压栈的。此时选择登出按钮后,返回到login页面,但是再次选择back按钮,又会出现了堆栈中的其他页面,原因就是这种情况下login之前没有被压栈,其上也没有其他的activity,而且mainactivity又是singletop类型,因此中间生成的activity无法被销毁。

解决办法3: 在用户选择登出的时候,为intent添加tag FLAG_ACTIVITY_CLEAR_TOP ,这个需要保证要回到的页面在堆栈中要存在,这里就是mainactivity,的确是存在的,然后调用这个方法,会将mainactivity之上的所有的activity都销毁掉,就可以简单达到这个目的了。当已经存在的activity实例处理新的intent时候,会调用onNewIntent()方法,这个需要执行的页面属性如果为singletop,那么这个要跳回的页面就不会被销毁,而只会销毁其上其他的历史页面。这个就很适合做登出功能。

FLAG_ACTIVITY_CLEAR_TOP

清除包含此Activity的Task中位于该Activity实例之上的其他Activity实例。这种行为的 launchMode 属性没有对应的值,只能通过代码设置。

单独使用的情况:ABCD 启动 B ,会销毁B和B以上的实例 变成 AB ,B 重新执行onCreate -> onStart

配合FLAG_ACTIVITY_SINGLE_TOP使用,则 B 不会销毁只销毁B以上实例,然后B 执行onNewIntent -> onStart

 
5777390-e132b7bef71e695e.png
 
 
5777390-2af5a950fe1b945f.png
 

login页面登录成功后如下操作即可

 
5777390-301a9ba7d1d2d6ec.png
 
 
5777390-619fcb202fe2c9df.png
 
 
5777390-e358382bbdb686c4.png
 
 
5777390-87fbb564d9d2c5ed.png
 

Intent的Flag

我们在代码里面通过Intent启动Activity的时候可以添加flag,如 :

intent.addFlags(Intent.FLAG_ACTIVITY_XXX);

FLAG_ACTIVITY_BROUGHT_TO_FRONT

这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定。

FLAG_ACTIVITY_CLEAR_TASK

此Activity将变成一个新Task中新的最底端的Activity,所有的之前此Activity实例和包含该实例的Task都会被关闭,这个标识仅仅和FLAG_ACTIVITY_NEW_TASK联合起来才能使用。

FLAG_ACTIVITY_NEW_TASK

与launchMode="singleTask"一样的效果。

FLAG_ACTIVITY_CLEAR_TOP

清除包含此Activity的Task中位于该Activity实例之上的其他Activity实例。这种行为的 launchMode 属性没有对应的值,只能通过代码设置。

单独使用的情况:ABCD 启动 B ,会销毁B和B以上的实例 变成 AB ,B 重新执行onCreate -> onStart

配合FLAG_ACTIVITY_SINGLE_TOP使用,则 B 不会销毁只销毁B以上实例,然后B 执行onNewIntent -> onStart

配合FLAG_ACTIVITY_NEW_TASK则是singleTask效果

FLAG_ACTIVITY_SINGLE_TOP

与launchMode="singleTop"一样的效果。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

设置了的话该Activity则不出现在最近使用的列表中。

FLAG_ACTIVITY_FORWARD_RESULT

如果A需要onActivityResult中获取返回结果,startActivityForResult B,而B只是过渡页,启动C之后就finish掉了,需要在 C 中setResult返回给A就可以用到这个标志。

A -> B -> XXXXX(无论多少个过渡页)  设置 FLAG_ACTIVITY_FORWARD_RESULT 来启动 C ,之后该XXX过渡页finish - > C  ,那么C的结果返回给A

FLAG_ACTIVITY_NO_HISTORY

如果设置,新的Activity将不在历史stack中保留。用户一离开它,这个Activity就关闭了。

例如A启动B的时候,给B设置了FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY,那么:

A -> B -> C ,启动C 就算 B没有自行finish ,也会变为 AC

FLAG_ACTIVITY_NO_ANIMATION

启动的时候不执行动画。

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY

当用户点击Home,从历史中选择该Activity,系统会自动加上这个Flag。

FLAG_ACTIVITY_NO_USER_ACTION

在onPause()之前会调用onUserLeaving( )方法,如果使用了该标识,说明目标Activity不和用户交互,所以也就不需要回调onUserLeaving( )方法。

FLAG_ACTIVITY_REORDER_TO_FRONT

如果设置这个标记,新启动的Activity将会被放到它所属task的最前面

例如,假如有一个Task包含4个Activity:A,B,C,D.如果D通过调用startActivity( )来启动B,如果使用了这个标记,B将会排在这个task的最上面,也即现在的顺序变成了A,C,D,B。

如果使用了FLAG_ACTIVITY_CLEAR_TOP,这个标记将会被忽略。

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

如果设置该属性,并且这个Activity在一个新的Task中正在被启动或者被带到一个已经存在的Task的顶部,这时这个Task会被重置(即该Task中之前的Activity会被关闭),该Activity成为栈底第一个Activity。

FLAG_ACTIVITY_TASK_ON_HOME

把当前新启动的任务置于Home任务之上,也就是按back键从这个任务返回的时候会回到Home,即使这个不是他们最后看见的Activity。

注意这个标记必须和FLAG_ACTIVITY_NEW_TASK加上android:taskAffinity一起使用。

FLAG_DEBUG_LOG_RESOLUTION

用来调试,当设置这个标志的时候,在解析这个intent的时候,将会打出打印信息(queryIntent函数)。

FLAG_INCLUDE_STOPPED_PACKAGES 和 FLAG_DEBUG_LOG_RESOLUTION

从Android 3.1开始,给Intent定义了两个新的Flag,分别为FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES,用来控制Intent是否要对处于停止状态的App起作用,顾名思义:

FLAG_INCLUDE_STOPPED_PACKAGES:表示包含未启动的App

FLAG_EXCLUDE_STOPPED_PACKAGES:表示不包含未启动的App

值得注意的是,Android 3.1开始,系统向所有Intent的广播添加了FLAG_EXCLUDE_STOPPED_PACKAGES标志。这样做是为了防止广播无意或不必要地开启未启动App的后台服务。如果要强制调起未启动的App,后台服务或应用程序可以通过向广播Intent添加FLAG_INCLUDE_STOPPED_PACKAGES标志来唤醒。

FLAG_FROM_BACKGROUND

Intent不光可以在Acitivity里面start,还可以从service里面启动,这个参数就表示这个Intent是从后台服务发起的。

FLAG_GRANT_PERSISTABLE_URI_PERMISSION

区别于 FLAG_GRANT_READ_URI_PERMISSION 跟 FLAG_GRANT_WRITE_URI_PERMISSION, URI权限会持久存在即使重启,直到明确的用 revokeUriPermission(Uri, int) 撤销。 这个flag只提供可能持久授权。但是接收的应用必须调用ContentResolver的takePersistableUriPermission(Uri, int)方法实现 。

FLAG_GRANT_PERSISTABLE_URI_PERMISSION

Uri 权限授予任何原始授权URI前缀匹配的URI。

FLAG_GRANT_PERSISTABLE_URI_PERMISSION

结合FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION 使用。

Uri 权限授予任何原始授权URI前缀匹配的URI。如果没有这个标志则必须精确匹配Uri了。

FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION

临时访问读权限和写权限 。Intent的接受者将被授予 INTENT 数据 uri 或者 在ClipData 上的读/写权限。

FLAG_RECEIVER_FOREGROUND

当发送广播时,允许其接受者 在前台运行的拥有更高的优先级,更短的超时间隔。

FLAG_RECEIVER_NO_ABORT

如果是有序广播,不要允许接收者中断广播播。

FLAG_RECEIVER_REGISTERED_ONLY

设置之后就不能通过xml来注册监听这个广播了,必须动态注册。

很多毒病程序为了证保自己被止终后可以再次行运,都会在xml中册注一些系统广播,妄图利用这些系统高频广播来实现自动启。

比如在老版本的android系统中,毒病程序可以通过监听TIME_TICK来动启自己的service后台行运,做一些秘隐的作工,而且就算自己被kill失落了,也能很快重新动启。

而一旦这些系统广播加了flag FLAG_RECEIVER_REGISTERED_ONLY,这些毒病程序就没辙了。

例如系统的TIME_TICK广播,由AlarmManagerService发送,我们看源码可以看到

mTimeTickSender = PendingIntent.getBroadcast(context, 0,

new Intent(Intent.ACTION_TIME_TICK).addFlags(

Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0);

这样就不能监听ACTION_TIME_TICK来自启动了。

FLAG_RECEIVER_REPLACE_PENDING

这个Flag 将会将之前的Intent 替代掉。加了这个Flag,在发送一系列的这样的Intent 之后,中间有些Intent 有可能在你还没有来得及处理的时候,就被替代掉了。

FLAG_ACTIVITY_NEW_DOCUMENT(原FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)

可以跟FLAG_ACTIVITY_MULTIPLE_TASK结合使用,当只用自己的时候相当于Manifast中 android.R.attr.documentLaunchMode="intoExisting",当跟FLAG_ACTIVITY_MULTIPLE_TASK 结合使用相当于 Manifast中android.R.attr.documentLaunchMode="always"。

FLAG_ACTIVITY_RETAIN_IN_RECENTS

默认情况下通过FLAG_ACTIVITY_NEW_DOCUMENT启动的Activity在关闭之后,Task中的记录会相对应的删除。如果为了能够重新启动这个Activity你想保留它,就可以使用者个flag,最近的记录将会保留在接口中以便用户去重新启动。接受该Flag的Activity可以使用autoRemoveFromRecents去复写这个request或者调用Activity.finishAndRemoveTask( )方法。

FLAG_ACTIVITY_MULTIPLE_TASK

这个标识用来创建一个新的task栈,并且在里面启动新的activity(所有情况,不管系统中存在不存在该activity实例),经常和FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用。这上面两种使用场景下,如果没有带上FLAG_ACTIVITY_MULTIPLE_TASK标识,他们都会使系统搜索存在的task栈,去寻找匹配intent的一个activity,如果没有找到就会去新建一个task栈;但是当和FLAG_ACTIVITY_MULTIPLE_TASK一起使用的时候,这两种场景都会跳过搜索这步操作无条件的创建一个新的task。和FLAG_ACTIVITY_NEW_TASK一起使用需要注意,尽量不要使用该组合除非你完成了自己的顶部应用启动器,他们的组合使用会禁用已经存在的task栈回到前台的功能。

taskAffinity 和 allowTaskReparenting

taskAffinity用于指定当前Activity所关联的Task,allowTaskReparenting用于配置是否允许该Activity可以更换从属Task,通常情况二者连在一起使用,用于实现把一个应用程序的Activity移到另一个应用程序的Task中。

allowTaskReparenting用来标记Activity能否从启动的Task移动到taskAffinity指定的Task,默认是继承至application中的allowTaskReparenting=false,如果为true,则表示可以更换;false表示不可以。

例如在A应用中启动了B应用的Activity,如果设置allowTaskReparenting=true,则Activity允许从A的Task移动到B的Task。但如果A被启动之后,Activity就会回到A的Task中。

比较保守的实现方式,简言之就是记录activity堆栈信息,然后实现跳转到登录页面和清除中间的activity。存在的问题在于当第一次安装app,用户直接选择home键,再次启动会kill掉主页面,也就是即便声明了singletop类型依然会被destroy掉!但是如果选择了back键销毁应用然后再次操作,就不会有这个问题了,非常奇怪!这里暂时做一下记录,后面有时间再细纠。

private void registerActivityListener() {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

@Override

                public void onActivityCreated(Activity activity, Bundle bundle) {

if (activity.getClass().equals(MainActivity.class) &&isActivityExisted(MainActivity.class)){

MainActivity mainActivity =findActivity(MainActivity.class);

//                        activity.finish();

                        finishAllActivity();

                    }

pushActivity(activity);

                }

@Override

                public void onActivityStarted(Activity activity) {

}

@Override

                public void onActivityResumed(Activity activity) {

}

@Override

                public void onActivityPaused(Activity activity) {

}

@Override

                public void onActivityStopped(Activity activity) {

}

@Override

                public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

}

@Override

                public void onActivityDestroyed(Activity activity) {

if (null==mActivitys||mActivitys.isEmpty()){

return;

                    }

if (mActivitys.contains(activity)){

//监听到 Activity销毁事件 将该Activity 从list中移除

                        popActivity(activity);

                    }

}

});

        }

}

private void registerActivityLifecycleListener(){

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

@Override

            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

}

@Override

            public void onActivityStarted(Activity activity) {

Log.d("onActivityStarted", "" + activity.getClass());

                activityCount +=1;

                if (activityCount >0) {

isActive =true;

                }

if (!isAlive){

isAlive =true;

                }

}

@Override

            public void onActivityResumed(Activity activity) {

}

@Override

            public void onActivityPaused(Activity activity) {

}

@Override

            public void onActivityStopped(Activity activity) {

activityCount -=1;

                if (activityCount <=0) {

isActive =false;

                }

}

@Override

            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

}

@Override

            public void onActivityDestroyed(Activity activity) {

}

});

    }

/**

    * @param activity 作用说明 :添加一个activity

*/

    public void pushActivity(Activity activity) {

mActivitys.add(activity);

        Log.d("activityList:size:+" ,"" +mActivitys.size());

    }

/**

    * @param activity 作用说明 :删除一个activity

*/

    public void popActivity(Activity activity) {

mActivitys.remove(activity);

        Log.d("activityList:size:-" ,"" +mActivitys.size());

    }

/**

* get current Activity 获取当前Activity(栈中最后一个压入的)

*/

    public static ActivitycurrentActivity() {

if (mActivitys ==null||mActivitys.isEmpty()) {

return null;

        }

Activity activity =mActivitys.get(mActivitys.size()-1);

        return activity;

    }

/**

* 结束当前Activity(栈中最后一个压入的)

*/

    public static void finishCurrentActivity() {

if (mActivitys ==null||mActivitys.isEmpty()) {

return;

        }

Activity activity =mActivitys.get(mActivitys.size()-1);

        finishActivity(activity);

    }

/**

* 结束指定的Activity

*/

    public static void finishActivity(Activity activity) {

if (mActivitys ==null||mActivitys.isEmpty()) {

return;

        }

if (activity !=null) {

mActivitys.remove(activity);

            activity.finish();

            activity =null;

        }

}

/**

* 结束指定类名的Activity

*/

    public static void finishActivity(Class cls) {

if (mActivitys ==null||mActivitys.isEmpty()) {

return;

        }

for (Activity activity :mActivitys) {

if (activity.getClass().equals(cls)) {

finishActivity(activity);

            }

}

}

/**

* 按照指定类名找到activity

*

    * @param cls

    * @return

    */

    public static T findActivity(Class cls) {

T targetActivity =null;

        if (mActivitys !=null) {

for (Activity activity :mActivitys) {

if (activity.getClass().equals(cls)) {

targetActivity = (T)activity;

break;

                }

}

}

return targetActivity;

    }

public static boolean isActivityExisted(Class cls){

if (mActivitys !=null) {

for (Activity activity :mActivitys) {

if (activity.getClass().equals(cls)) {

return true;

                }

}

}

return false;

    }

/**

    * @return 作用说明 :获取当前最顶部activity的实例

*/

    public static ActivitygetTopActivity() {

Activity mBaseActivity =null;

        synchronized (mActivitys) {

final int size =mActivitys.size() -1;

            if (size <0) {

return null;

            }

mBaseActivity =mActivitys.get(size);

        }

return mBaseActivity;

    }

/**

    * @return 作用说明 :获取当前最顶部的acitivity 名字

*/

    public StringgetTopActivityName() {

Activity mBaseActivity =null;

        synchronized (mActivitys) {

final int size =mActivitys.size() -1;

            if (size <0) {

return null;

            }

mBaseActivity =mActivitys.get(size);

        }

return mBaseActivity.getClass().getName();

    }

/**

* 结束所有Activity

*/

    public static void finishAllActivity() {

if (mActivitys ==null) {

return;

        }

for (Activity activity :mActivitys) {

activity.finish();

        }

mActivitys.clear();

    }

public static void finishToMainActivity() {

if (mActivitys ==null ||mActivitys.isEmpty()) {

return;

        }

Activity temp =null;//= mActivitys.get(mActivitys.size() - 1);

        for (Activity activity :mActivitys) {

if (!activity.getClass().equals(MainActivity.class)) {

activity.finish();

            }else{

temp = activity;

            }

}

mActivitys.clear();

        if (temp ==null){

return;

        }

mActivitys.add(temp);

    }

//    public static Activity finishLatestActivity(){

//        Activity temp = mActivitys.get(mActivitys.size() - 1);

//        finishActivity(temp);

//    }

    /**

* 退出应用程序

*/

    public  static void appExit() {

try {

finishAllActivity();

        }catch (Exception e) {

}

}

    android:name=".uicommonframework.Application"

    android:allowBackup="true"

    android:label="@string/app_name"

    android:supportsRtl="true"

    android:theme="@style/AppTheme">

        android:name=".uicommonframework.MainActivity"

        android:launchMode="singleTop"

        android:screenOrientation="portrait"

        android:theme="@style/WelcomeStyle1">

 

            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />

        android:name=".uicommonframework.LauncherFullScreen"

        android:theme="@style/WelcomeStyle2" />

        android:name=".LoginActivity"

        android:label="@string/title_activity_login"

        android:launchMode="singleTop"

        android:screenOrientation="portrait"

        android:theme="@style/Theme.AppCompat.NoActionBar"

        android:windowSoftInputMode="adjustPan|stateHidden" />

        android:name="RootActivity"

        android:launchMode="singleTop"

        android:screenOrientation="portrait" />

 

//选择登出键退出到登录页面

private void returnToMainActivity() {

Application.finishToMainActivity();

        Activity context = Application.getTopActivity();

        Intent intent =new Intent(context, MainActivity.class);

        intent.putExtra(MainActivity.INTENT_KEY_1, MainActivity.INTENT_KEY_1);

        context.startActivity(intent);

    }

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值