Activity
- Activity的启动和结束
- Activity的生命周期
- Activity的启动模式
- Intent(意图)
- Activity的数据发送和返回
Activity的启动和结束
- 从当前页面跳转到新页面,要用到startActivity方法
方法里要传入意图(Intent)对象, 代码如下
startActivity(new Intent(源页面.this, 目标页面.class));
- 从当前页面回到上一页面,相当于关闭当前页面,代码如下
finish();
Activity 生命周期
- Activity 类提供六个核心回调:
onCreate()、onStart()、onResume()、onPause()、onStop() 和 onDestroy()
简化图的简单说明
1.一个Activity被启动时,顺次执行 onCreate() 、onStart() 、onResume(),这个Activity从创建,到可见状态,最后到启动状态
2.当跳转到另一个Activity时,进入onPause()状态,此时已经是不可见状态,之后执行onStop()
3.当点按返回,会执行onRestart(),onStart() 、onResume(),再度变成可见状态
4.当从这个Activity退出,回到系统主页面时,会执行onPause() 、onStop() 、onDestroy() 、整个Activity被销毁
5.如果点跳转之后又立刻点击返回,那么就会出现上面的现象,onPause() 之后没有执行onStop() 、直接回到onResume(),我们说onStop() 是在页面完全消失后执行,那也就是说,因为快速的切换点击,页面还没有完全消失,就从onPause() 立刻回到了onResume()
6.当前应用已经退到后台,也就是执行完了onStop(),但还没有执行onDestroy() ,手机在运行着其他占用内存的应用,此时系统会为了有更大的内从空间,系统会杀掉onPause() ,onStop()状态的Activity
方法 | 状态 | 说明 |
---|---|---|
onCreate | 创建活动 | 把页面布局加载进内存,进入初始状态 |
onStart | 开始活动 | 把活动页面显示在屏幕上,进入了就绪状态 |
onResume | 恢复活动 | 活动页面进入活跃状态,能够与用户正常交互,例如允许响应用户的点击动作,允许用户输入文字等等 |
onPause | 暂停活动 | 页面进入暂停状态,无法与用户正常交互 |
onStop | 停止活动 | 页面将不在屏幕上显示 |
onDestroy | 毁灭活动 | 回收活动占用的系统资源,把页面从内存中清除 |
onRestart | 重启活动 | 重新加载内存中的页面数据 |
当一个Activity启动时,顺次执行 onCreate() 、onStart() 、onResume()
当一个Activity关闭时,顺次执行 onPasue() 、onStop() 、onDestroy()
- 状态切换
约定俗称的操作
在onCreate() 里做findViewById
在onDestroy() 里关闭网络连接,释放资源
在onResume() 里开启画面
在onPasue() 里关闭画面
Activity的启动模式
如果Activity已经启动过,并且在当前应用的Activity任务栈中,
- 默认启动模式 standard
- 栈顶复用模式 singleTask
- 栈顶复用模式 singleTop
- 全局唯一模式 singleInstance
1.在配置文件中指定启动模式
打开AndroidMainfest.xml, 给activity节点添加属性 android:launchMode,属性值填入standard表示采取标准模式,当然不添加属性的话默认就是标准模式。具体的activity节点配置内容如下:
<activity android:name=".MainActivity" android:launchMode="standard"/>
其中launchMode属性的几种取值说明
Intent类的启动标志 | 说明 |
---|---|
Intent.FLAG_ACTIVITY_NEW_TASK | 开辟一个新的任务栈,该值类似于 launchMode=“standard” ,不同之处在于,如果原来不存在活动栈,则FLAG_ACTIVITY_NEW_TASK会创建一个新栈 |
Intent.FLAG_ACTIVITY_SINGLE_TOP | 当栈顶为待跳转的活动实例时,则重用栈顶的实例,该值等同于launchMode=“singleTop” |
Intent.FLAG_ACTIVITY_CLEAR_TOP | 当栈中存在待跳转的活动实例时,则重新创建一个新的实例,并清除原实例上方的所有实例,该值与launchMode="singleTask"类似,但singleTask采取onNewIntent方法启动原任务,而FLAG_ACTIVITY_CLEAR_TOP采用先调用onDestroy在调用onCreate来创建新任务 |
Intent.FLAG_ACTIVITY_NO_HISTORY | 该标志于 launchMode=“standard” 情况类似,但栈中不保存新启动的活动实例,这样下次无论以何种方式在启动该实例,也要走standard模式的完整流程 |
Intent.FLAG_ACTIVITY_CLEAR_TASK | 该标志非常暴力,跳转到新页面时,栈中的原有实例都被清空,并要注意,该标志需要结合FLAG_ACTIVITY_NEW_TASK 使用,即setFlags方法的参数为"FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK" |
默认启动模式 standard
最常规的模式,先进后出,后进先出
栈顶复用模式 singleTask
与singleTop模式相似,只不过singleTop模式是只针对栈顶的元素,而singleTask模式下,如果task栈内存在目标Activity实例,则将task内的对应Activity实例之上的所有Activity弹出栈,并将对应Activity置于栈顶,获得焦点。
应用场景
程序的主界面:通常主界面不需要被创建多次
耗费系统资源的Activity:对于一些会很耗费资源的Activity,可以考虑设置成singleTask
栈顶复用模式 singleTop
全局唯一模式 singleInstance
在该模式下,会为目标Activity创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点,新的Task有且只有这一个Activity实例,如果已经创建过目标Activity实例,则不会创建新的Task,而是将之前创建过的Activity唤醒。
Intent(意图)
Intent是Android各个组件之间信息通信的桥梁,主要完成下面工作
- 标明本次通信请求从哪里来,到哪里去,要怎么走
- 发起方携带本次通信需要的数据内容,接收方从收到的意图里解析数据
- 发起方若想判断接收方的处理结果,意图就要负责让接收方返回结果数据
Intent的组成部分
元素名称 | 设置方法 | 说明与用途 |
---|---|---|
Component | setComponent | 组件,它指定意图的来源和目标 |
Action | setAction | 动作,它指定意图的动作行为 |
Data | setData | 即Uri,它指定动作要操纵的数据路径 |
Category | addCategory | 类别,它指定意图的操作类别 |
Type | setType | 数据类型,它指定消息的数据类型 |
Extras | putExtras | 扩展信息,它指定装载的包裹信息 |
Flags | setFlags | 标志位,它指定活动的启动标志 |
1.显式Intent,直接指定来源活动与目标活动,属于精确匹配。它有三种构建方式:
- 在Intent的构造函数中指定
- 调用意图对象的setClass方法指定
- 调用意图对象的setComponent方法指定
在构建一个意图对象时,需要指定两个参数,第一个参数表示跳转的源页面 源Activity.this
第二个参数表示待跳转的页面 目标Activity.class,具体的意图构建方式有如下3种:
(1) 在Intent的构造函数中指定
Intent intent = new Intent(this, nextActivity.class);
(2) 调用意图对象的setClass方法指定
Intent intent = new Intent();
intent.setClass(this, nextActivity.class);
(3) 调用意图对象的setComponent方法指定
Intent intent = new Intent();
ComponentName component = new ComponentName(this, nextActivity.class);
intent.setComponent(component);
2.隐式Intent,没有明确指定要跳转的目标活动,只给出一个动作字符串让系统自动匹配,属于模糊匹配
通常App不希望向外部暴露活动名称,只给出一个事先定义好的标记字符串,约定俗成的按图索骥,隐式Intent便起到了标记过滤作用,这个动词名称字符串可以是自己定义的动作,也可以是已有的系统动作,常见系统动作的取值说明表
Intent类的系统动作常量名 | 系统动作常量值 | 说明 |
---|---|---|
ACTION_MAIN | android.intent.action.MAIN | APP启动时的入口 |
ACTION_VIEW | android.intent.action.VIEW | 向用户显示数据 |
ACTION_SEND | android.intent.action.SEND | 分享内容 |
ACTION_CALL | android.intent.action.CALL | 直接拨号 |
ACTION_DIAL | android.intent.action.DIAL | 准备拨号 |
ACTION_SENDTO | android.intent.action.SENDTO | 发送短信 |
ACTION_ANSWER | android.intent.action.ANSWER | 接听电话 |
动作名称即可以通过setAction方法指定,也可以通过构造函数Intent(String action)直接生成意图对象,但由于是模糊匹配有局限,当想指定更详细的信息时,可以用Uri和Category来制定,
Uri数据可通过构造函数Intent(String action, Uri uri)在生成对象时一起指定,也可以通过setData方法指定(setData这个名字有歧义,实际相当于setUri),Category可通过addCategory方法指定,之所以用add而不用set方法,是因为一个意图允许同时设置多个Category,方便一起过滤
Activity的数据发送和返回
给下一个Activity发送数据
Intent使用Bundle对象存放待传递的数据信息
Bundle对象操作各类型数据的读写方法
数据类型 | 读方法 | 写方法 |
---|---|---|
整型 | getInt | putInt |
浮点型 | getFloat | putFloat |
双精度型 | getDouble | putDouble |
布尔型 | getBoolean | putBoolean |
字符串 | getString | putString |
字符串数组 | getStringArray | putStringArray |
字符串列表 | getStringArrayList | putStringArrayList |
可序列化结构 | getSerializable | putSerializable |
public class MainActivity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
TextView textView = findViewById(androidx.core.R.id.text);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//创建意图
Intent intent = new Intent(MainActivity2.this, MainActivity.class);
//创建Bundle用于绑定要传递的数据
Bundle bundle = new Bundle();
bundle.putString("name","Tom");
bundle.putString("age","10");
//把绑定好数据的Bundle传递给意图
intent.putExtras(bundle);
//调转画面
startActivities(intent);
}
});
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
TextView textView = findViewById(androidx.core.R.id.text);
//接收上个画面传过来的数据
Bundle bundle = getIntent().getExtras();
String name = bundle.getString("name");
String age = bundle.getString("age");
textView.setText(name + age);
}
}
给上一个Activity返回数据
- 上一个页面打包好请求数据,调用startActivityForResult方法执行跳转动作
- 下一个页面接收并解析请求数据,进行相应处理
- 下一个页面在返回上一个页面时,打包应答数据并调用setResult方法返回数据包裹
- 上一个页面重写方法onActivityResult,解析获得下一个页面的返回数据
public class ResActivity extends AppCompatActivity implements View.OnClickListener {
private ActivityResultLauncher<Intent> register;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_res);
TextView textView = findViewById(R.id.t_request);
textView.setText("ABCDE");
findViewById(R.id.btn_res).setOnClickListener(this);
TextView textView1 = findViewById(R.id.t_response);
textView1.setText("1234");
register = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result != null){
Intent intent = result.getData();
if (intent != null && result.getResultCode() == Activity.RESULT_OK){
Bundle bundle = intent.getExtras();
String msg = bundle.getString("Message");
textView1.setText(msg);
}
}
}
});
}
@Override
public void onClick(View view) {
Intent intent = new Intent(this, ResponseActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name", "Tom");
bundle.putString("age", "int");
intent.putExtras(bundle);
//已过时的方法
//startActivityForResult();
register.launch(intent);
}
}
public class ResponseActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_response);
TextView textView = findViewById(R.id.t_request);
Bundle bundle = getIntent().getExtras();
String name = bundle.getString("name");
String age = bundle.getString("age");
textView.setText("" + name + age);
findViewById(R.id.btn_response).setOnClickListener(this);
}
@Override
public void onClick(View view) {
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("Message", "this is test");
intent.putExtras(bundle);
//结果返回
setResult(Activity.RESULT_OK, intent);
finish();
}
}
如何在在Activity里利用strings.xml的字符串
利用上文对象Context里的getString方法,因为Activity本身已经继承了Context类,
所以可以直接用他的getString方法
String name = getString(R.string.name);
代码中获取元数据
获取元数据信息有三步
- 调用getPackageManager方法获得当前应用的包管理器
- 调用包管理器的getActivityInfo方法获得当前Activity的信息对象
- 活动信息对象的metaData是Bundle包裹类型,调用包裹对象的getString方法,获取指定的值
AndroidManifest.xml
<activity
android:name=".ResActivity"
android:exported="true"
android:theme="@style/Theme.MyApplication.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="name" android:value="tom"/>
</activity>
Activity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_res);
TextView textView = findViewById(R.id.t_request);
//获取应用包管理器
PackageManager packageManager = getPackageManager();
try {
//从应用包管理器中获取当前活动信息
ActivityInfo activityInfo = packageManager.getActivityInfo(getComponentName(), packageManager.GET_META_DATA);
//从活动信息里取得metaData
Bundle metaData = activityInfo.metaData;
//从Bundle获取内部信息
String name = metaData.getString("name");
textView.setText(name);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}