《疯狂Android讲义》学习笔记 -- 深入理解Activity

来源:互联网 发布:绩效考核软件 编辑:程序博客网 时间:2024/05/19 23:26

Activity的说明

         Activity是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作。每个Activity都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可以小于屏幕并浮动在其他窗口之上。
        一个应用通常由多个彼此松散联系的Activity组成。一般会指定应用中的某个Activity为"主"Activity,即首次启动应用时呈现给用户的那个Activity。而且每个Activity均可启动另一个Activity,以便执行不同的操作。每次新的Activity启动时,前一个Activity便会停止,但系统会在堆栈("返回栈")中保留该Activity。当新Activity启动时,系统会将其推送到返回栈上,并取得用户焦点。返回栈遵循"后进先出"堆栈机制,因此,当用户完成当前Activity并按"返回"按钮时,系统会从堆栈中将其弹出(并销毁),然后恢复前一Activity。
        当一个Activity因某个新Activity启动而停止时,系统会通过该Activity的生命周期回调方法通知其这一状态变化Activity因状态变化-系统是创建Activity、停止Activity、恢复Activity还是销毁Activity-而收到的回调方法可能有若干种,每一种回调方法都会为您提供执行与该状态变化相应的特定操作的机会。例如,停止时,您的Activity应释放任何大型对象,例如网络或数据库连接。当Activity恢复时,您可以重新获取所需资源,并恢复执行中断的操作。这些状态转变都是Activity生命周期的一部分。

Activity的基本使用

创建Activity

        要创建Activity,您必须创建Activity的子类(或使用其现有子类)。您需要在子类中实现Activity在其生命周期的各种状态之间转变时(例如创建Activity、停止Activity、恢复Activity或销毁Activity)系统调用的回调方法。两个最重要的回调方法是:
onCreate()
        您必须实现此方法。系统会在创建您的Activity时调用此方法。您应该在实现内初始化Activity的必需组件。最重要的是,您必须在此方法内调用setContentView(),以定义Activity用户界面的布局。
onPause()
        系统将此方法作为用户离开Activity的第一个信号(但并不总是意味着Activity会被销毁)进行调用。您通常应该在此方法内确认在当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。
        您还应使用几种其他生命周期回调方法,以便提供流畅的 Activity 间用户体验,以及处理导致您的 Activity 停止甚至被销毁的意外中断。 后文的管理Activity生命周期部分对所有生命周期回调方法进行了阐述。

启动、关闭Activity

        正如前面介绍的,一个Android应用通常都会包含多个Activity,但只有一个Activity会作为程序的入口----当该Android应用运行时将会自动启动并执行该Activity。至于应用中的其他Activity,通常都由入口Activity启动,或由入口Activity启动的Activity启动。
        Activity启动其他Activity有如下两个方法。
  • startActivity(Intent intent):启动其他Activity。
  • startActivityForResult(Intent intent, int requestCode):以指定的请求码(requestCode)启动Activity,而且程序将会等到新启动Activity的结果(通过重写onActivityResult(...)方法来获取)。
        启动Activity时可指定一个requestCode参数,该参数代表了启动Activity的请求码。这个请求码的值由开发者根据业务自行设置,用于标识请求来源。
        上面两个方法都用到了Intent参数,Intent是Android应用里各个组件之间通信的重要方式,一个Activity通过Intent来表达自己“意图”----想要启动哪个组件,被启动的组件即可是Activity组件,也可是Service组件。
        Android为关闭Activity准备了如下两个方法:
  • finish():结束当前Activity。
  • finishActivity(int requestCode):结束以startActivityForResult(Intent intent, int requestCode)方法启动的Activity。
        下面的示例程序示范了如何启动Activity,并允许程序在两个Activity之间切换。
Intent intent = new Intent(StartActivity.this, SecondActivity.class);
startActivity(intent);
// 结束当前Activity
finish();

使用Bundle在Activity之间交换数据

        当一个Activity启动另一个Activity时,常常会有一些数据需要传过去。在Activity之间进行数据交换主要是通过Intent,把需要交换的数据放入Intent即可。
        Intent提供了多个重载的方法来“携带”额外的数据,如下所示:
  • putExtras(Bundle data):向Intent中放入需要“携带”的数据包。
  • Bundle getExtras():取出Intent所“携带”的数据包。
  • putExtra(String name, Xxx value):向Intent中按key-value对的形式存入数据。
  • getXxxExtra(String name):从Intent中按key取出指定类型的数据。
        从上面的介绍不难看出,Intent主要通过Bundle对象来携带数据,因此Intent提供了putExtras()和getExtras()两个方法。除此之外,Intent也提供了多个重载的putExtra(String name, Xxx value)、getXxxExtra(String name)方法,那么这些方法存,取的数据在哪里呢?其实Intent提供的putExtra(String name, Xxx value)、getXxxExtra(String name)方法,只是一个便捷的方法,这些方法是直接存、取Intent所携带的Bundle中的数据
        下面的示例程序示范了两个Activity之间如何通过Bundle交换数据。
FirstActivity发送数据:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
Bundle data = new Bundle();
data.putSerializable("person",p);
intent.putExtras(data);
startActivity(intent);
 
SecondActivity接收数据:
Intent intent = getIntent();
Person p = intent.getSerializableExtra("person");

在清单文件中声明 Activity

        您必须在清单文件中声明您的 Activity,这样系统才能访问它。 要声明您的 Activity,请打开您的清单文件,并将 <activity>元素添加为<application>元素的子项。例如:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >

启动其他Activity并返回结果  

        前面已经提到,Activity还提供了一个startActivityForResult(Intent intent, int requestCode)方法来启动其他Activity。该方法用于启动指定Activity,
而且期望获取指定Activity返回的结果。这种请求对于实际应用也是很常见的,例如应用程序第一个界面需要用户进行选择----但需要选择的列表数据比较复杂,必须启动另一个Activity让用户选择。当用户在第二个Activity选择完成后,程序返回第一个Activity,第一个Activity必须能获取并显示用户在第二个Activity选择的结果。在这种应用场景下,也是通过Bundle进行数据交换的。
        为了获取被启动的Activity所返回的结果,需要从两方面着手:
  • 当前Activity需要重写onActivityResult(int requestCode, int resultCode, Intent intent),当被启动的Activity返回结果时,该方法将会被触发,其中requestCode代表请求码,而resultCode代表Activity返回的结果码,这个结果码也是由开发者根据业务自行设定的。
  • 被启动的Activity需要调用setResult()方法设置处理结果。
        一个Activity中可能包含多个按钮,并调用多个startActivityForResult(Intent intent, int requestCode)方法来打开多个不同的Activity处理不同的业务,当这些新Activity关闭后,系统都将回调前面Activity的onActivityResult(int requestCode, int resultCode, Intent intent)方法。为了知道该方法是由哪个请求的结果所触发的,可利用requestCode请求码;为了知道返回的数据来自于哪个新的Activity,可利用resultCode结果码。
        下面通过一个示例来介绍如何启动Activity并获取被启动Activity的结果。
FirstActivity的操作
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
// 启动指定Activity并等待返回的结果,其中0是请求码,用于标识该请求
startActivityForResult(intent,0);
 
// 重写该方法,该方法以回调的方式来获取指定Activity返回的结果
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if(requestCode == 0 && resultCode == 0) {
// 取出Intent里的Extras数据
Bundle data = intent.getExtras();
...
}
}
 
SecondActivity操作
// 获取启动该Activity之前的Activity对应的Intent
Intent intent = getIntent();
intent.putExtra("key","value");
SecondActivity.this.setResult(0,intent);
SecondActivity.this.finish();

Activity的回调机制

         所谓回调,在实现具有通用性质的应用架构时非常常见:对于一个具有通用性质的程序架构来说,程序架构完成整个应用的通用功能、流程,但在某个特定的点上,需要一段业务相关的代码----通用的程序架构无法实现这段代码,那么程序架构会在这点上留一个“空”。
        对于Java程序来说,程序架构在某个点上留的“空”,可以以如下两种方式存在。
  • 以接口形式存在:该接口由开发者实现,实现该接口时将会实现该接口的方法,那么通用的程序架构就会回调该方法来完成业务相关的处理。
  • 以抽象方法(以可以是非抽象方法)的形式存在:这就是Activity的实现形式。这些特点的点上方法已经被定义了,如onCreate、onActivityResult等方法,开发者可以选择性地重写这些方法,通过的程序架构就会回调该方法来完成业务相关的处理。
        前面介绍的事件处理也用到了回调机制:当开发者开发一个组件时,如果开发者需要该组件能响应特定的事件,可以选择性地实现该组件的特定方法----当用户在该组件上激发某个事件时,该组件上特定的方法就会回到。
        Activity的回调机制也与此类似,当Activity被部署在Android应用中之后,随着应用程序的运行,Android会不断地在不同的状态之间切换,该Activity中特定的方法就会被回调----开发者就可以选择性地重写这些方法来加入业务相关的处理。

Activity的生命周期

         通过实现回调方法管理 Activity 的生命周期对开发强大而又灵活的应用至关重要。 Activity 的生命周期会直接受到 Activity 与其他 Activity、其任务及返回栈的关联性的影响。
        Activity 基本上以四种状态存在:
  • 活动状态:当前Activity位于前台,用户可见,可以获得焦点。
  • 暂停状态:其他Activity位于前台,该Activity依然可见,只是不能获取焦点。也就是说,另一个 Activity 显示在此 Activity 上方,并且该 Activity 部分透明或未覆盖整个屏幕。 暂停的 Activity 处于完全活动状态(Activity 对象保留在内存中,它保留了所有状态和成员信息,并与窗口管理器保持连接),但在内存极度不足的情况下,可能会被系统终止。
  • 停止状态:该Activity不可见,失去焦点。 已停止的 Activity 同样仍处于活动状态(Activity 对象保留在内存中,它保留了所有状态和成员信息,但与窗口管理器连接)。 不过,它对用户不再可见,在他处需要内存时可能会被系统终止。
  • 销毁状态:该Activity结束,或Activity所在的Dalvik进程被结束。
        如果 Activity 处于暂停或停止状态,系统可通过要求其结束(调用其 finish() 方法)或直接终止其进程,将其从内存中删除。(将其结束或终止后)再次打开 Activity 时,必须重建。

实现生命周期回调

        当一个 Activity 转入和转出上述不同状态时,系统会通过各种回调方法向其发出通知。 所有回调方法都是挂钩,您可以在 Activity 状态发生变化时替代这些挂钩来执行相应操作。 以下框架 Activity 包括每一个基本生命周期方法:
public class ExampleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The activity is being created.
}
@Override
protected void onStart() {
super.onStart();
// The activity is about to become visible.
}
@Override
protected void onResume() {
super.onResume();
// The activity has become visible (it is now "resumed").
}
@Override
protected void onPause() {
super.onPause();
// Another activity is taking focus (this activity is about to be "paused").
}
@Override
protected void onStop() {
super.onStop();
// The activity is no longer visible (it is now "stopped")
}
@Override
protected void onDestroy() {
super.onDestroy();
// The activity is about to be destroyed.
}
}
注:正如以上示例所示,您在实现这些生命周期方法时必须始终先调用超类实现,然后再执行任何操作。
这些方法共同定义 Activity 的整个生命周期。您可以通过实现这些方法监控 Activity 生命周期中的三个嵌套循环:
  • Activity 的整个生命周期发生在 onCreate() 调用与 onDestroy() 调用之间。您的 Activity 应在 onCreate() 中执行“全局”状态设置(例如定义布局),并释放 onDestroy() 中的所有其余资源。例如,如果您的 Activity 有一个在后台运行的线程,用于从网络上下载数据,它可能会在 onCreate() 中创建该线程,然后在 onDestroy() 中停止该线程。
  • Activity 的可见生命周期发生在 onStart() 调用与 onStop() 调用之间。在这段时间,用户可以在屏幕上看到 Activity 并与其交互。 例如,当一个新 Activity 启动,并且此 Activity 不再可见时,系统会调用 onStop() 。您可以在调用这两个方法之间保留向用户显示 Activity 所需的资源。 例如,您可以在 onStart() 中注册一个 BroacastReceiver 以监控影响 UI 的变化,并在用户无法再看到您显示的内容时在 onStop() 中将其取消注册。在 Activity 的整个生命周期,当 Activity 在对用户可见和隐藏两种状态中交替变化时,系统可能会多次调用 onStart() 和 onStop() 。
  • Activity 的前台生命周期发生在 onResume() 调用与 onPause() 调用之间。在这段时间,Activity 位于屏幕上的所有其他 Activity 之前,并具有用户输入焦点。 Activity 可频繁转入和转出前台 — 例如,当设备转入休眠状态或出现对话框时,系统会调用 onPause()。 由于此状态可能经常发生转变,因此这两个方法中应采用适度轻量级的代码,以避免因转变速度慢而让用户等待。
        图 1 说明了这些循环以及 Activity 在状态转变期间可能经过的路径。矩形表示回调方法,当 Activity 在不同状态之间转变时,您可以实现这些方法来执行操作。

  图 1. Activity 生命周期。
        表 1 列出了相同的生命周期回调方法,其中对每一种回调方法做了更详细的描述,并说明了每一种方法在 Activity 整个生命周期内的位置,包括在回调方法完成后系统能否终止 Activity。
        表 1. Activity 生命周期回调方法汇总表。
方法说明是否能事后终止?后接onCreate()首次创建 Activity 时调用。 您应该在此方法中执行所有正常的静态设置 — 创建视图、将数据绑定到列表等等。 系统向此方法传递一个 Bundle 对象,其中包含 Activity 的上一状态,不过前提是捕获了该状态(请参阅后文的保存Activity状态)。始终后接onStart()。否onStart()onRestart()在 Activity 已停止并即将再次启动前调用。始终后接 onStart()否onStart()onStart()在 Activity 即将对用户可见之前调用。

如果 Activity 转入前台,则后接 onResume(),如果 Activity 转入隐藏状态,则后接 onStop()。

否onResume()
或onStop()onResume()在 Activity 即将开始与用户进行交互之前调用。 此时,Activity 处于 Activity 堆栈的顶层,并具有用户输入焦点。始终后接 onPause()否onPause()onPause()当系统即将开始继续另一个 Activity 时调用。 此方法通常用于确认对持久性数据的未保存更改、停止动画以及其他可能消耗 CPU 的内容,诸如此类。 它应该非常迅速地执行所需操作,因为它返回后,下一个 Activity 才能继续执行。

如果 Activity 返回前台,则后接 onResume(),如果 Activity 转入对用户不可见状态,则后接 onStop()。

是onResume()或onStop()onStop()在 Activity 对用户不再可见时调用。如果 Activity 被销毁,或另一个 Activity(一个现有 Activity 或新 Activity)继续执行并将其覆盖,就可能发生这种情况。

如果 Activity 恢复与用户的交互,则后接 onRestart(),如果 Activity 被销毁,则后接 onDestroy()。

是onRestart()或onDestroy()onDestroy()在 Activity 被销毁前调用。这是 Activity 将收到的最后调用。 当 Activity 结束(有人对 Activity 调用了 finish()),或系统为节省空间而暂时销毁该 Activity 实例时,可能会调用它。 您可以通过 isFinishing() 方法区分这两种情形。是无        名为“是否能事后终止?”的列表示系统是否能在不执行另一行 Activity 代码的情况下,在方法返回后随时终止承载 Activity 的进程。 有三个方法带有“是”标记:({@linkandroid.app.Activity#onPause onPause()}、onStop() 和 onDestroy())。由于 onPause() 是这三个方法中的第一个,因此 Activity 创建后,onPause( ) 必定成为最后调用的方法,然后才能终止进程 — 如果系统在紧急情况下必须恢复内存,则可能不会调用 onStop() 和 onDestroy()因此,您应该使用 onPause() 向存储设备写入至关重要的持久性数据(例如用户编辑)。不过,您应该对 onPause() 调用期间必须保留的信息有所选择,因为该方法中的任何阻止过程都会妨碍向下一个 Activity 的转变并拖慢用户体验。
        在是否能在事后终止?列中标记为“否”的方法可从系统调用它们的一刻起防止承载 Activity 的进程被终止。 因此,在从 onPause() 返回的时间到 onResume() 被调用的时间,系统可以终止 Activity。在 onPause() 被再次调用并返回前,将无法再次终止 Activity。

保存Activity状态

        Activity的生命周期的引言部分简要提及,当 Activity 暂停或停止时,Activity 的状态会得到保留。 确实如此,因为当 Activity 暂停或停止时,Activity 对象仍保留在内存中 — 有关其成员和当前状态的所有信息仍处于活动状态。 因此,用户在 Activity 内所做的任何更改都会得到保留,这样一来,当 Activity 返回前台(当它“继续”)时,这些更改仍然存在。
        不过,当系统为了恢复内存而销毁某项 Activity 时,Activity 对象也会被销毁,因此系统在继续 Activity 时根本无法让其状态保持完好,而是必须在用户返回 Activity 时重建 Activity 对象。但用户并不知道系统销毁 Activity 后又对其进行了重建,因此他们很可能认为 Activity 状态毫无变化。 在这种情况下,您可以实现另一个回调方法对有关 Activity 状态的信息进行保存,以确保有关 Activity 状态的重要信息得到保留:onSaveInstanceState()
        系统会先调用 onSaveInstanceState(),然后再使 Activity 变得易于销毁。系统会向该方法传递一个 Bundle,您可以在其中使用 putString() 和 putInt() 等方法以名称-值对形式保存有关 Activity 状态的信息。然后,如果系统终止您的应用进程,并且用户返回您的 Activity,则系统会重建该 Activity,并将 Bundle 同时传递给 onCreate() 和 onRestoreInstanceState()。您可以使用上述任一方法从 Bundle 提取您保存的状态并恢复该 Activity 状态。如果没有状态信息需要恢复,则传递给您的 Bundle是空值(如果是首次创建该 Activity,就会出现这种情况)。

        图 2. 在两种情况下,Activity 重获用户焦点时可保持状态完好:系统在销毁 Activity 后重建 Activity,Activity 必须恢复之前保存的状态;系统停止 Activity 后继续执行 Activity,并且 Activity 状态保持完好。
        :无法保证系统会在销毁您的 Activity 前调用 onSaveInstanceState(),因为存在不需要保存状态的情况(例如用户使用“返回”按钮离开您的 Activity 时,因为用户的行为是在显式关闭 Activity)。 如果系统调用 onSaveInstanceState(),它会在调用 onStop() 之前,并且可能会在调用 onPause() 之前进行调用。
        不过,即使您什么都不做,也不实现 onSaveInstanceState(),Activity 类的 onSaveInstanceState() 默认实现也会恢复部分 Activity 状态。具体地讲,默认实现会为布局中的每个 View 调用相应的 onSaveInstanceState() 方法,让每个视图都能提供有关自身的应保存信息。Android 框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复对 UI 所做的任何可见更改。例如,EditText小部件保存用户输入的任何文本,CheckBox 小部件保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小部件提供一个唯一的 ID(通过 android:id 属性)。如果小部件没有 ID,则系统无法保存其状态。
        尽管 onSaveInstanceState() 的默认实现会保存有关您的Activity UI 的有用信息,您可能仍需替换它以保存更多信息。例如,您可能需要保存在 Activity 生命周期内发生了变化的成员值(它们可能与 UI 中恢复的值有关联,但默认情况下系统不会恢复储存这些 UI 值的成员)。
        由于 onSaveInstanceState() 的默认实现有助于保存 UI 的状态,因此如果您为了保存更多状态信息而替换该方法,应始终先调用 onSaveInstanceState() 的超类实现,然后再执行任何操作。 同样,如果您替换 onRestoreInstanceState() 方法,也应调用它的超类实现,以便默认实现能够恢复视图状态。
        :由于无法保证系统会调用 onSaveInstanceState() ,因此您只应利用它来记录 Activity 的瞬态(UI 的状态)— 切勿使用它来存储持久性数据,而应使用 onPause() 在用户离开 Activity 后存储持久性数据(例如应保存到数据库的数据)。

Activity的加载模式

        正如前面介绍Activity配置时提到的,配置Activity时可指定android:launchMode属性,该属性用于配置该Activity的加载模式,该属性支持如下4个属性值。
  1. standard:标准模式,这是默认的加载模式。
  2. singleTop:Task顶单例模式。
  3. singleTask:Task内单例模式。
  4. singleInstance:全局单例模式。
        可能有读者会问:为什么要为Activity指定加载模式呢?加载模式有什么用?在讲解Activity的加载模式之前,先介绍Android对Activity的管理:Android采用Task来管理多个Activity,当我们启动一个应用时,Android就会为之创建了一个Task,然后启动这个应用的入口Activity(即<intent-filter.../>)中配置为MAIN和LAUNCHER的Activity。
        Activity的Task是一个有点麻烦的概念----因为Android并没有为Task提供API,因此开发者无法真正去访问Task,只能调用Activity的getTaskId()方法来获取它所在的Task的ID。事实上,我们可以把Task理解成Activity栈,Task以栈的形式来管理Activity:先启动的Activity被放在Task栈底,后启动的Activity被放在Task栈顶。
        那么Activity的加载模式,就负责管理实例化、加载Activity的方式、并可以控制Activity与Task之间的加载关系。
        下面详细介绍这4中加载模式。

1、standard模式

        每次通过这种模式来启动目标Activity时,Android总会为目标Activity创建一个新的实例,并将该Activity添加到当前Task栈中----这种模式不会启动新的Task,新Activity将被添加到原有的Task中。

2、singleTop模式

        如果当前任务的顶部已存在 Activity 的一个实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建 Activity 的新实例。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例(但前提是位于返回栈顶部的 Activity 并不是 Activity 的现有实例)。
        例如,假设任务的返回栈包含根 Activity A 以及 Activity B、C 和位于顶部的 D(堆栈是 A-B-C-D;D 位于顶部)。收到针对 D 类 Activity 的 Intent。如果 D 具有默认的 “standard” 启动模式,则会启动该类的新实例,且堆栈会变成 A-B-C-D-D。但是,如果 D 的启动模式是 “singleTop”,则 D 的现有实例会通过 onNewIntent() 接收 Intent,因为它位于堆栈的顶部;而堆栈仍为 A-B-C-D。但是,如果收到针对 B 类 Activity 的 Intent,则会向堆栈添加 B 的新实例,即便其启动模式为 “singleTop” 也是如此。
        :为某个 Activity 创建新实例时,用户可以按“返回”按钮返回到前一个 Activity。 但是,当 Activity 的现有实例处理新 Intent 时,则在新 Intent 到达 onNewIntent() 之前,用户无法按“返回”按钮返回到 Activity 的状态。

3、singleTask模式

        采用这种加载模式的Activity在同一个栈内只有一个实例,当系统采用singleTask模式启动目标Activity时,可分为如下三种情况:
  • 如果将要启动的目标Activity不存在,系统将会创建目标Activity的实例,并将它加入Task栈顶。
  • 如果将要启动的目标Activity已经位于Task栈顶,此时与singleTop模式的行为相同。
  • 如果将要启动的目标Activity已经存在、但没有位于Task栈顶,系统将会把位于该Activity上面的所有Activity移出Task栈,从而使得目标Activity转入栈顶。

4、singleInstance模式

        这种加载模式下,系统保证无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例,并会使用一个全新的Task栈来装载该Activity实例。
        当系统采用singleInstance模式启动目标Activity时,可分为如下两种情况:
  • 如果将要启动的目标Activity不存在,系统会先创建一个全新的Task、再创建目标Activity的实例,并将它加入新的Task的栈顶。
  • 如果将要启动的目标Activity已经存在,无论它位于哪个应用程序中,无论它位于哪个Task中,系统将会把该Activity所在的Task转到前台,从而使用该Activity显示出来。
        需要指出的是,采用singleInstance模式加载Activity总是位于Task栈顶,采用singleInstance模式加载Activity所在Task只包含该Activity。
1 0
原创粉丝点击