文章目录
- Activity 的启动模式
- standard
- singleTop
- singleTask
- singleInstance
- 技巧
- 了解当前界面是哪个 Activity
- 随时随地退出程序
- 启动活动的最佳写法
Activity 的启动模式
- standard:默认的启动方式,每次启动一个活动都会重新创建
- singleTop:如果该活动处于栈顶,则不会创建新活动,不处于栈顶则创建新活动
- singleTask:如果返回栈中存在该活动,那么将该活动之上的所有活动统统出栈,将该活动置于栈顶,如果不存在该活动则创建
- singleInstance:会重新启用一个新的返回栈来创建该活动,通常用于共享活动的实例
standard
standard
是 Activity 默认的启动模式,在不进行显式指定的情况下,都使用这种模式。
在本模式下,每当启动一个新的活动,系统不会确认返回栈中是否已存在这个活动,而是直接创建该活动的一个新的实例并入栈。
singleTop
如果启动活动时发现返回栈栈顶已经是这个活动,则认为可以直接使用它,不会创建新的实例。
在 AndroidManifest.xml
中添加如下配置:
singleTask
每次启动该活动时,系统首先会在返回栈中检查是否存在该活动的实例:
- 如果发现已经存在则直接使用该实例,并把在这个活动之上的活动统统出栈;
- 如果没有就创建新的实例。
举个例子:
- 我们为 FirstActivity 配置 singleTask ;
- 然后在 FirstActivity 的 Button 上启动 SecondActivity;
- 然后 SecondActivity 的 Button 上回到 FirstActivity。
我们可以得到这样的推断:
- 在 SecondActivity 中启动 FirstActivity 时,会发现返回栈中已经存在一个 FirstActivity 的实例;
- 于是 SecondActivity 会从返回栈中出栈,而 FirstActivity 重新成为了栈顶活动;
- 因此 FirstActivity 的 onRestart()方法 和 SecondActivity 的 onDestroy() 方法会得到执行。
singleInstance
在本模式下,活动会启用一个新的返回栈来管理(如果 singleTask 模式指定了不同的 taskAffinity,也会启动一个新的返回栈)。如果我们想实现其他程序和我们的程序可以共享某个活动的实例,就可以用 singleInstance 模式创建一个单独的返回栈来管理这个活动,以此实现让任意应用程序都可以调用该活动。
举个例子:
- FirstActivity 通过 Button 跳转到 SecondActivity;
- SecondActivity 通过 Button 跳转到 ThirdActivity,且修改 SecondActivity 的启动模式为
singleInstance
:
<activity android:name=".SecondActivity" android:launchMode="singleInstance">
倘若我们通过 log
来监测三个活动分属的返回栈,我们会发现:
SecondActivity
是存放在一个单独的返回栈里的。
而在 ThirdActivity 中按 Back
键,那么会直接返回到 FirstActivity,再按下返回键会回到 SecondActivity,再按下返回键才会退出程序。
原理很简单:
- 由于 FirstActivity 和 ThirdActivity 是存放在同一个返回栈里的,当在 ThirdActivity 的界面按下
Back
键, ThirdActivity 会从返回栈中出栈,那么 FirstActivity 就成为了栈顶活动显示在界面上。 - 然后在 FirstActivity 界面再次按下
Back
键,这时当前的返回栈已经空了,于是就显示了另一个返回栈的栈顶活动,即 SecondActivity。 - 最后再次按下
Back
键,这时所有返回栈都已经空了,也就自然退出了程序。
技巧
了解当前界面是哪个 Activity
新建一个普通 java
类 —— BaseActivity :
public class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);Log.d("BaseActivity", getClass().getSimpleName());}
}
然后让每个活动类都改为继承自 BaseActivity,这样就可以在 LogCat
中看到当前类名。
随时随地退出程序
当在程序运行中的一个活动,要退出可能会需要按多次 Back
键(按 Home
键只是把程序挂起,并没有退出程序。),所以需要一个直接退出活动的方法。
新建一个 ActivityCollector 类作为活动管理器:
public class ActivityCollector {public static List<Activity> activities = new ArrayList<Activity>();public static void addActivity(Activity activity){ // 用于向 List 中添加一个 Activityactivities.add(activity);}public static void removeActivity(Activity activity){ // 用于从 List 中删除一个 Activityactivities.remove(activity);}public static void finishAll(){ // 用于将 List 中存储的所有活动全部销毁for (Activity activity : activities)if (!activity.isFinishing())activity.finish();}
}
接下来修改 BaseActivity:
public class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);Log.d("BaseActivity", getClass().getSimpleName());ActivityCollector.addActivity(this);// 将当前正在创建的活动添加到活动管理器 ActivityCollector 里}@Overrideprotected void onDestroy(){super.onDestroy();ActivityCollector.removeActivity(this);// 将一个马上要销毁的活动从管理器 ActivityCollector 中移除}
}
以后,不管想在什么地方退出程序,只需要 ActivityCollector.finishAll()
就可以了。
保险起见也可以在销毁所有活动后杀掉当前进程,以保证程序完全退出:
android.os.Process.killProcess(android.os.Process.myPid());
killProcess()
方法用于杀掉一个进程,它接收一个进程 id
参数,通过 myPid()
方法来获得当前程序的进程 id
。需要注意的是 killProcess()
方法只能用于杀掉当前程序的进程,我们不能使用这个方法去杀掉其他程序。
启动活动的最佳写法
之前启动的方法是构建一个新的 Intent
,然后调用 startActivity()
或者 startActivityForResult()
来启动活动。如果 SecondActivity 需要用到两个字符串参数,那么 FirstActivity 可能会写成下面这样:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data1", s1);
intent.putExtra("extra_data2", s2);
startActivity(intent);
这样虽然可以,但是在 SecondActivity 是一个黑盒子时,是会出现问题的。可以修改 SecondActivity 的代码:
public static void actionStart(Context context, String s1, String s2){Intent intent = new Intent(context, SecondActivity.class);intent.putExtra("extra_data1", s1);intent.putExtra("extra_data2", s2);context.startActivity(intent);
}
和以往不同,在 actionStart()
方法中完成了 Intent
的构建,而非 onClick()
方法,所有 SecondActivity 中需要的数据都是通过 actionStart()
方法的参数传递过来的,然后把它们存储到 Intent
中,最后调用 startActivity()
方法启动。
这样在 onClick()
方法中只需一行代码即可启动 SecondActivity :
button1.setOnclickListener(new OnclickListener() {@Overridepublic void onclick(View v) {SecondActivity.actionStart(FirstActivity.this, "data1", "data2");}
});