一、理解 Tasks and Back Stack(任务和后台堆栈)
一个 App 对应一个 Task,该app 内的所有 activity 被安排在一个后台堆栈里。
多窗口模式下:一个windows下可能由多个 Task,系统为每个窗口单独管理 Task。当启动一个app时,系统为其启动一个Task。其它App进入后台(每个堆栈内的 acitivity处于停止状态)。注意:如果后台任务过多,系统会销毁后台活动以释放内存,活动的状态也会丢失。
二、管理任务
Android管理任务和后台堆栈的方式,如上所述,通过将所有的活动连续地放在同一任务和“后进先出”的堆栈中,对于大多数应用程序来说是非常好的,并且不必担心您的活动与任务或它们如何退出有关。
但是,您可能会决定要中断这种正常行为:
- 也许您希望应用程序中的一个活动在启动时 启动一个新任务(而不是放在当前任务中);
- 当启动一个活动时,你想提出它的一个现有实例,而不是在堆栈的顶部创建一个新实例;
- 当用户离开任务时,除了根活动,,希望清除堆栈。
您可以在<activity>清单元素中使用属性,并在传递给startActivity()的意图中使用标志。
在这方面,您可以使用的主体 <activity>
属性如下:
- taskAffinity
- launchMode
- allowTaskReparenting
- clearTaskOnLaunch
- alwaysRetainTaskState
- finishOnTaskLaunch
您可以使用的主要意图标志是:
- FLAG_ACTIVITY_NEW_TASK
- FLAG_ACTIVITY_CLEAR_TOP
- FLAG_ACTIVITY_SINGLE_TOP
三、定义启动模式
在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作。在Android中Activity的启动模式决定了Activity的启动运行方式。
启动模式允许您定义活动的新实例如何与当前任务关联。你可以用两种方式定义不同的启动模式:
- 使用清单文件 当在清单文件中声明一个活动时,可以指定活动在启动时应如何与任务相关联。
- 使用
Intent flags
当调用startActivity()
时,可以在意图中包含一个标志,声明新的活动如何(或是否)与当前任务相关联。
因此,如果活动A启动活动B,活动B可以在其清单中定义它应该如何与当前任务相关联(如果有的话),而且活动A也可以请求活动B应该如何与当前任务相关联。如果两个活动都定义了活动B应该如何与任务相关联,那么活动A的请求(如意图中定义的)将被授予活动B的请求(如清单中定义的)。
注意:一些启动模式 在清单文件中可用 ,但不可用作为意图的标志;同样地,一些启动模式作为 flags 可用,但在清单中不能定义。
使用清单文件
Activity启动模式设置:
Activity的四种启动模式:
-
standard (默认模式)
系统在启动的任务中创建活动的新实例并将意图路由到该任务。 该活动可以被实例化多次,每个实例可以属于不同的任务,并且一个任务可以具有多个实例。 -
singleTop
如果活动的实例已经存在于当前任务的顶部,则系统通过调用其onNewIntent()
方法将意图路由到该实例,而不是创建活动的新实例。
该活动可以多次实例化,每个实例可以属于不同的任务,并且一个任务可以有多个实例(但仅当在后台堆栈顶部的活动不是活动的现有实例)。
- singleTask 系统创建一个新任务并实例化新任务的根的活动。但是,如果活动的实例已经存在于单独的任务中,则系统通过调用其
onNewIntent()
方法将意图路由到现有实例,而不是创建新实例。一次只能存在一个活动实例。
注意:虽然活动在一个新任务中启动,但后退按钮仍然将用户返回到先前的活动。
- singleInstance 与“singleTask ”相同,只是系统没有将任何其他活动放入实例中。该活动始终是其任务的唯一成员,该活动启动的任何活动在单独的任务中打开。
在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。
举例
1.standard
public class MainActivity extends AppCompatActivity { TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = findViewById(R.id.textView); tv.setText(this.toString()); } // 按钮点击事件 public void launchStandard(View view) { startActivity(new Intent(this, MainActivity.class)); tv.setText(this.toString()); }}
由此可知,这种 Standard
模式是 每次都会创建新的Activity对象,当点击返回按钮时,他会将栈顶(当前Activity)消灭,然后跳到下一层。这种模式可能大多数情况下不是我们需要的,因为对系统性能的消耗过大。
**2.singleTop **
从上面的解释中即可知道,在每次使用新的Activity时会自动检测栈顶的当前Activity是否是需要引用的Activity,如果是则直接引用此Activity,而不会创建新的Activity。public class MainActivity extends AppCompatActivity { TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = findViewById(R.id.textView); tv.setText(this.toString()); } public void launchStandard(View view) { startActivity(new Intent(this, SingleTopActivity.class)); tv.setText(this.toString()); }}
public class SingleTopActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_single_top); tv = findViewById(R.id.textView); tv.setText(this.toString()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Toast.makeText(this,this.getClass().getSimpleName(),Toast.LENGTH_LONG).show(); } public void launchSingleTop(View view) { startActivity(new Intent(this, SingleTopActivity.class)); tv.setText(this.toString()); }}
当在SingleTopActivity
点击 "启动当前页面按钮" 时,不会创建新的对象,因为该Activity 处在栈顶,不会创建新的对象,但是会回调 onNewIntent()
方法。
3.singleTask
此启动模式和singleTop在名字上即可看出区别,即singleTop每次只检测当前栈顶的Activity是否是我们需要请求创建的,而singleTask则会检测栈中全部的Activity对象,从上向下,如果检测到是我们所请求的则会消灭此Activity对象上面的对象,直接把检测到的我们需要的Activity置为栈顶。
** 4.SingleInstance**
此启动模式和我们使用的浏览器工作原理类似,我们都知道在多个程序中访问浏览器时,如果当前浏览器没有打开,则打开浏览器,否则会在当前打开的浏览器中访问。此模式会节省大量的系统资源,因为他能保证要请求的Activity对象在当前的栈中只存在一个。
上面即为Android中的四种启动模式,我们在开发Android项目时会经常使用到,巧妙设置Activity的启动模式会节省系统开销和程序运行效率。