我们在做Android app 的时候 需要理解activity的栈 包括一些活动的销毁
就像叠加一堆书 每个新打开的活动放在最上面 当然会有一些特殊的情况 需要自己设置 下面会一一讲解
下面示例官网给的图示例
用户使用app一个界面是一个活动 需要对应的xml布局文件 例如刚打开app就是一个活动
假如第一个界面是登陆界面 他为activity1 然后登陆进去会显示你的个人界面 这时为activtiy2
再切换一个activity3 关闭界面3 这时界面3的部分缓存就会消失 这时就要适当运用数据库和saved方法保存重要数据
下面是官网的讲解
理解任务和后台堆栈
任务是用户在执行特定作业时与之交互的活动的集合。活动按堆栈排列 - 后堆栈 - 按每个活动打开的顺序排列。例如,电子邮件应用可能有一个活动来显示新消息列表。当用户选择消息时,将打开一个新活动以查看该消息。此新活动将添加到后台堆栈。如果用户按下“ 返回”按钮,则表示新活动已完成并从堆栈中弹出。
当应用程序在多窗口环境中同时运行时 ,在Android 7.0(API级别24)及更高版本中受支持,系统会为每个窗口单独管理任务; 每个窗口可能有多个任务。对于 在Chromebook上运行的Android应用程序也是如此:系统基于每个窗口管理任务或任务组。
设备主屏幕是大多数任务的起始位置。当用户触摸应用程序启动器中的图标(或主屏幕上的快捷方式)时,该应用程序的任务将进入前台。如果应用程序不存在任务(最近未使用该应用程序),则会创建一个新任务,该应用程序的“主”活动将作为堆栈中的根活动打开。
当前活动从另一个活动开始时,新活动将被推到堆栈顶部并获得焦点。之前的活动仍在堆栈中,但已停止。当活动停止时,系统将保留其用户界面的当前状态。当用户按下“ 返回” 按钮时,当前活动将从堆栈顶部弹出(活动被销毁),之前的活动将恢复(其UI的先前状态将恢复)。堆栈中的活动永远不会重新排列,只能在当前活动启动时从堆栈推送和弹出到堆栈中,并在用户使用Back退出时弹出按钮。因此,后堆栈作为“后进先出”对象结构操作。图1显示了这种行为,时间轴显示了活动之间的进度以及每个时间点的当前后栈。
表示任务中的每个新活动如何将项添加到后台堆栈。当用户按下“ 返回”按钮时,将破坏当前活动并恢复先前的活动。
如果用户继续按Back,则弹出堆栈中的每个活动以显示前一个活动,直到用户返回主屏幕(或任务开始时运行的任何活动)。从堆栈中删除所有活动后,该任务不再存在。
图2.两个任务:任务B在前台接收用户交互,而任务A在后台,等待恢复。
任务是一个内聚单元,当用户开始新任务或通过主页按钮进入主屏幕时,可以移动到“背景” 。在后台,任务中的所有活动都会停止,但任务的后台堆栈保持不变 - 任务在发生另一项任务时完全失去焦点,如图2所示。然后任务可以返回到“前景“所以用户可以从中断的地方继续前进。例如,假设当前任务(任务A)在其堆栈中有三个活动 - 在当前活动下有两个活动。用户按下Home 按钮,然后从应用启动器启动一个新的应用程序。出现主屏幕时,任务A进入后台。当新应用程序启动时,系统会使用自己的一系列活动为该应用程序(任务B)启动任务。在与该应用程序交互之后,用户再次返回Home并选择最初启动任务A的应用程序。现在,任务A进入前台 - 其堆栈中的所有三个活动都完好无损,并且堆栈顶部的活动将恢复。此时,用户还可以通过返回主页并选择启动该任务的应用程序图标(或从“ 最近”屏幕中选择应用程序的任务)切换回任务B. 这是Android上的多任务处理的一个示例。
注意:可以在后台同时保存多个任务。但是,如果用户同时运行许多后台任务,系统可能会开始销毁后台活动以恢复内存,从而导致活动状态丢失。
图3.单个活动多次实例化。
由于后备堆栈中的活动永远不会重新排列,如果您的应用程序允许用户从多个活动启动特定活动,则会创建该活动的新实例并将其推送到堆栈(而不是带来任何先前的活动实例)到顶部)。因此,您的应用中的一个活动可能会被多次实例化(甚至来自不同的任务),如图3所示。因此,如果用户使用“ 后退”按钮向后导航,则活动的每个实例都按顺序显示被打开(每个都有自己的UI状态)。但是,如果您不希望多次实例化活动,则可以修改此行为。有关如何执行此操作将在后面的“ 管理任务”一节中讨论。
总结活动和任务的默认行为:
当活动A启动活动B时,活动A停止,但系统保留其状态(例如滚动位置和输入到表单中的文本)。如果用户在活动B中按下“ 返回”按钮,则活动A将恢复其状态。
当用户通过按Home键离开任务时,当前活动将停止,其任务将进入后台。系统保留任务中每个活动的状态。如果用户稍后通过选择开始任务的启动器图标来恢复任务,则任务将到达前台并恢复堆栈顶部的活动。
如果用户按下“ 返回”按钮,则会从堆栈中弹出当前活动并将其销毁。堆栈中先前的活动已恢复。当活动被销毁时,系统 不会保留活动的状态。
活动可以多次实例化,甚至可以从其他任务实例化。
最后一个特殊情况可以把一个界面活动保存到最底部
启动一个新的活动用到startActivity intent传值 同时还可以返回结果的startActivityForResult
可以用add或 append方法返回数据
官网建议功能清单注册
启动模式允许您定义活动的新实例与当前任务的关联方式。您可以通过两种方式定义不同的启动模式:
使用清单文件
在清单文件中声明活动时,可以指定活动在启动时应如何与任务关联。
使用Intent标志
当您调用时startActivity(),您可以在其中包含一个标志Intent,声明新活动应如何(或是否)与当前任务相关联。
因此,如果活动A启动活动B,活动B可以在其清单中定义它应该如何与当前任务相关联(如果有的话),活动A也可以请求活动B应该如何与当前任务相关联。如果两个活动都定义了活动B应该如何与任务相关联,则活动A的请求(如意图中所定义)将遵循活动B的请求(如其清单中所定义)。
注意:清单文件可用的某些启动模式不可用作intent的标志,同样,某些启用模式可用作intent的标志,无法在清单中定义。
讲述这些方法的简介
在清单文件中声明活动时,您可以使用
该launchMode属性指定有关如何将活动启动到任务的指令。您可以为launchMode 属性分配四种不同的启动模式 :
"standard" (默认模式)
默认。系统在启动它的任务中创建活动的新实例,并将意图路由到该实例。活动可以多次实例化,每个实例可以属于不同的任务,一个任务可以有多个实例。
"singleTop"
如果活动的实例已存在于当前任务的顶部,则系统通过调用其onNewIntent()方法将意图路由到该实例,而不是创建活动的新实例。活动可以多次实例化,每个实例可以属于不同的任务,一个任务可以有多个实例(但只有当后端堆栈顶部的活动不是活动的现有实例时)。
例如,假设任务的后台堆栈由根活动A组成,其中活动B,C和D位于顶部(堆栈为ABCD; D位于顶部)。意图到达类型D的活动。如果D具有默认"standard"启动模式,则启动该类的新实例并且堆栈变为ABCDD。但是,如果D的启动模式是"singleTop",D的现有实例接收意图onNewIntent(),因为它位于堆栈的顶部 - 堆栈仍然是ABCD。但是,如果意图到达类型B的活动,则将新的B实例添加到堆栈中,即使其启动模式为"singleTop"。
注意:创建活动的新实例时,用户可以按“ 返回”按钮返回上一个活动。但是,当活动的现有实例处理新意图时,用户无法在新意图到达之前按“ 返回”按钮返回活动状态onNewIntent()。
"singleTask"
系统创建新任务并在新任务的根目录下实例化活动。但是,如果活动的实例已存在于单独的任务中,则系统会通过调用其onNewIntent()方法将意图路由到现有实例 ,而不是创建新实例。一次只能存在一个活动实例。
注意:虽然活动在新任务中启动,但“ 后退”按钮仍会将用户返回到上一个活动。
"singleInstance"。
相同"singleTask",区别在于:系统不启动任何其他活动纳入控股实例的任务。活动始终是其任务的唯一成员; 任何由此开始的活动都在一个单独的任务中打开。
作为另一个示例,Android浏览器应用程序声明Web浏览器活动应始终在其自己的任务中打开 - 通过singleTask在
无论活动是在新任务中启动还是在与启动它的活动相同的任务中启动,“ 返回”按钮始终会将用户带到上一个活动。但是,如果启动指定singleTask启动模式的活动,则如果后台任务中存在该活动的实例,则将整个任务带到前台。此时,后端堆栈现在包括堆栈顶部提出的任务中的所有活动
图4.表示如何将具有启动模式“singleTask”的活动添加到后台堆栈。如果活动已经是具有自己的后台堆栈的后台任务的一部分,那么整个后台堆栈也会在当前任务的基础上出现。
有关在清单文件中使用启动模式的更多信息,请参阅
注意:您为具有该launchMode属性的活动指定的行为可以被包含在启动您的活动的intent中的标记覆盖,如下一节中所述。
下面讲述intent 过滤器
使用Intent标志
启动活动时,您可以通过在传递到的intent中包含标志来修改活动与其任务的默认关联startActivity()。您可以用来修改默认行为的标志是:
FLAG_ACTIVITY_NEW_TASK
在新任务中启动活动。如果任务已在您正在启动的活动上运行,则该任务将被带到前台,并恢复其上一个状态,并且活动将接收新的意图onNewIntent()。
这会产生与"singleTask" launchMode上一节中讨论的值相同的行为。
FLAG_ACTIVITY_SINGLE_TOP
如果正在启动的活动是当前活动(在后台堆栈的顶部),则现有实例将接收调用onNewIntent(),而不是创建活动的新实例。
这会产生与"singleTop" launchMode上一节中讨论的值相同的行为。
FLAG_ACTIVITY_CLEAR_TOP
如果正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是销毁其上的所有其他活动,并将此意图传递给活动的恢复实例(现在开启)顶部),通过onNewIntent())。
launchMode 生成此行为的属性没有值。
FLAG_ACTIVITY_CLEAR_TOP最常用的是 FLAG_ACTIVITY_NEW_TASK。当一起使用时,这些标志是一种在另一个任务中定位现有活动并将其置于可以响应意图的位置的方法。
注意:如果指定活动的启动模式是 "standard",它也将从堆栈中删除,并在其位置启动新实例以处理传入的意图。这是因为在启动模式下,总是为新意图创建一个新实例"standard"。
处理亲和力
该亲和力表示活动更喜欢哪个任务属于。默认情况下,同一应用程序中的所有活动都具有彼此的关联。因此,默认情况下,同一个应用程序中的所有活动都希望处于同一任务中。但是,您可以修改活动的默认关联。在不同应用中定义的活动可以共享亲和力,或者可以为同一应用中定义的活动分配不同的任务亲和力。
您可以使用 元素的taskAffinity属性修改任何给定活动的亲缘关系
该taskAffinity 属性采用字符串值,该值必须与元素中声明的默认包名称唯一,因为系统使用该名称来标识应用程序的默认任务关联。
亲和力在两种情况下起作用:
当启动活动的意图包含 FLAG_ACTIVITY_NEW_TASK 标志时。
默认情况下,新活动将启动到调用的活动的任务中startActivity()。它被调到与调用者相同的后栈。但是,如果传递的意图 startActivity() 包含FLAG_ACTIVITY_NEW_TASK 标志,则系统会查找另一个任务以容纳新活动。通常,这是一项新任务。但是,它不一定是。如果已存在与新活动具有相同亲缘关系的现有任务,则会将活动启动到该任务中。如果没有,它开始一项新任务。
如果此标志导致活动开始新任务,并且用户按下主页按钮以离开它,则必须有某种方式让用户导航回任务。某些实体(例如通知管理器)总是在外部任务中启动活动,从不作为自己的一部分,因此它们总是放入FLAG_ACTIVITY_NEW_TASK它们传递给的意图中 startActivity()。如果您有可以由可能使用此标志的外部实体调用的活动,请注意用户有一种独立的方式返回已启动的任务,例如使用启动器图标(任务的根活动)有一个CATEGORY_LAUNCHERintent过滤器;请参阅下面的Starting a task部分。
当活动的属性设置为。 allowTaskReparenting"true"
在这种情况下,当该任务到达前台时,活动可以从它开始的任务移动到它具有亲和力的任务。
例如,假设在所选城市中报告天气状况的活动被定义为旅行应用程序的一部分。它与同一应用程序中的其他活动(默认应用程序关联)具有相同的亲和力,并允许使用此属性重新生成父项。当您的某个活动启动天气报告者活动时,它最初属于与您的活动相同的任务。但是,当旅行应用程序的任务到达前台时,天气报告者活动将重新分配给该任务并显示在其中。
提示:如果APK文件从用户的角度包含多个“应用”,您可能希望使用该taskAffinity 属性为与每个“应用”关联的活动分配不同的亲和力
清理后栈
如果用户长时间离开任务,系统将清除除根活动之外的所有活动的任务。当用户再次返回任务时,仅还原根活动。系统以这种方式运行,因为在很长一段时间之后,用户可能已经放弃了之前正在做的事情并返回任务以开始新的事情。
您可以使用一些活动属性来修改此行为:
alwaysRetainTaskState
如果将此属性设置为"true"任务的根活动,则不会发生刚才描述的默认行为。即使经过很长一段时间,任务仍会保留堆栈中的所有活动。
clearTaskOnLaunch
如果将此属性设置为"true"任务的根活动,则只要用户离开任务并返回到该任务,就会将堆栈清除为根活动。换句话说,它与之相反 。即使在离开任务片刻之后,用户也始终以初始状态返回任务。 alwaysRetainTaskState
finishOnTaskLaunch
此属性类似clearTaskOnLaunch,但它在单个活动上运行,而不是在整个任务上运行。它还可以导致任何活动消失,包括根活动。当它设置为时"true",活动仍然是当前会话的任务的一部分。如果用户离开然后返回任务,它将不再存在
开始一项任务
您可以将活动设置为任务的入口点,方法是为其"android.intent.action.MAIN"指定具有指定操作和"android.intent.category.LAUNCHER" 指定类别的intent过滤器 。代码格式规范
intent-filter>
...
activity>
这种意图过滤器会导致活动的图标和标签显示在应用程序启动器中,从而为用户提供启动活动并返回其在启动后随时创建的任务的方法。
第二种能力很重要:用户必须能够离开任务,然后使用此活动启动器返回该任务。为此,标志着活动一如既往启动任务,这两种启动模式"singleTask"和 "singleInstance",应使用只有当活动有一个 ACTION_MAIN 和CATEGORY_LAUNCHER过滤器。例如,想象一下,如果缺少过滤器会发生什么:一个intent启动一个"singleTask"活动,启动一个新任务,并且用户花一些时间在该任务中工作。然后用户按下主页 按钮。该任务现在发送到后台并且不可见。现在用户无法返回任务,因为它未在应用启动器中显示。
对于您不希望用户能够返回活动的情况,请将
这里代码示例
功能清单代码示例
package="com.liziyang.dall"> //可以在这里加入权限 注意可能为危险权限 需6.0动态权限申请 当申请一个组中的一个 //整个组的权限申请成功 //同时可以使用第三方平台 如高德地图的key android:allowBackup="true" //图标 注意图片的屏幕大小适应 分辨率 android:icon="@mipmap/ic_launcher" //这里是显示顶部label的文字 可在string中修改 android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" //全屏可以在功能清单的主题中设置 还可以在活动的oncreate方法中设置去除tools android:theme="@style/AppTheme"> //活动都需要在功能清单中注册 否则编译失败 这个为自己命名的java继承活动类 //必须有这一行 其他都可以没有 //信使过滤器 //还可以自己提供一个接口用来让别人访问自己的这个activity //例如qq微信的授权登陆 或文件选择打开器 //活动的类 这里可以限制横屏运行 或竖屏 因为屏幕旋转会造成活动重建 //2018谷歌中国大会也提出了屏幕锁定也进行了调整 就是不再使用竖屏锁定和自动旋转 //即将使用自动旋转和锁定方向 这需要攻城狮的注意 //当然也可以查看通信商信息 例如中国的电信 移动 联通 像腾讯大王卡就是这样做出来的 //在腾讯的软件上他查看本地通信信号反馈位置 gprs地图定位 卫星定位和WiFi定位 //2018谷歌中国大会上讲述了当用户不打开gprs 不再可以使用定位 当此软件在前台正常使用 //在后台为了增加电池使用时间 进行了限制 android:name=".Main2Activity" android:label="@string/title_activity_main2" //任务栈 在这里设置 用来保存状态 等 默认是standed 可以不用添加 android:launchMode="standard"> //在这里是系统默认启动方式standard android:name=".Main3Activity" android:label="@string/title_activity_main3" //这里让main3这个类在任务栈的顶层 android:launchMode="singleTop">
ingleTop的讲解 即如果该activity在栈顶就不会调用创建新的实例 如果不在栈顶就会调用创建新的实例 都会调用onNewIntent
package com.liziyang.dall;
import android.content.Intent;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.Date;
public class Main3Activity extends Activity {
private TextView textView3,textView5;
private Button button4,button5;
//singleTop的讲解 即如果该activity在栈顶就不会调用创建新的实例 如果不在栈顶就会调用创建新的实例 都会调用onNewIntent
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate ( savedInstanceState );
setContentView ( R.layout.activity_main3 );
textView3=findViewById ( R.id.textView3 );
textView5=findViewById ( R.id.textView5);
textView3.setText ( this.toString () );
button4=findViewById ( R.id.button4);
button5=findViewById ( R.id.button5 );
button4.setOnClickListener ( new View.OnClickListener () {
@Override
public void onClick(View view) {
Intent intent=new Intent ( Main3Activity.this,Main3Activity.class );
startActivity ( intent );
}
} );
button5.setOnClickListener ( new View.OnClickListener () {
@Override
public void onClick(View view) {
Intent intent=new Intent ( Main3Activity.this,MainActivity.class );
startActivity ( intent );
}
} );
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent ( intent );
//设置本地时间显示 因为在启动自身会启动onNewIntent 这里保存本来用户最后的画面 activity的四个启动模式会用到这个 这里用的singletop
textView5.setText ( (CharSequence) new Date ().toLocaleString () );
}
}
布局文件
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".Main3Activity"> android:id="@+id/textView3" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="TextView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
这里仅供大家参考 这只是一个逻辑问题 用来让你理解他的活动规则
方便你对数据的处理