Android四大组件之一:Activity
- 前言
- 二、Android四大组件之一:Activity(活动)
- 2.1 活动基本介绍
- 2.2 活动的基本用法
- 2.2.1 如何在应用中弹出提示信息
- 2.2.2 如何在活动中添加Menu菜单(就一般右上角的三点)
- 2.2.3 如何实现活动跳转
- 2.2.5 如何实现向下一个活动传递数据
- 2.2.5 如何实现向上一个活动返回数据
- 2.2.6 如何销毁一个活动
- 2.3 活动的生命周期
- 2.3.1 返回栈
- 2.3.2 活动生命周期中的4种状态
- 2.3.3 活动生命周期内各个阶段的回调函数
- 2.3.4 如果活动被系统回收了,还想保留活动的数据,该怎么办?
- 2.4 活动的启动模式
- 2.4.1 standard
- 2.4.2 singleTop
- 2.4.3 singleTask
- 2.4.4 singleInstance
- 2.5 使用活动的小技巧
- 参考书籍:第一行代码
前言
本文讲解Android四大组件之一(活动)的基本用法,生命周期,启动模式等。
二、Android四大组件之一:Activity(活动)
2.1 活动基本介绍
活动是一种包含用户界面的组件,主要用于和用户进行交互。简单来说,一个活动就对应一个交互窗口。
2.2 活动的基本用法
2.2.1 如何在应用中弹出提示信息
Toast类下的静态方法makeText 可以在应用上弹出一个简单的提示信息,这是Android开发中比较常用的提示方法。
public static Toast makeText (Context context, //The context to use. Usually your Application or Activity object.
int resId, //可以字符串资源ID,也可以直接输入提示文本字符串
int duration)//信息显示时间: Either LENGTH_SHORT or LENGTH_LONG
示例代码
Toast.makeText(SecondActivity.this, "这是一条信息提示", Toast.LENGTH_SHORT).show();
在一个SecondActivity活动的程序中弹出一条信息提示。
2.2.2 如何在活动中添加Menu菜单(就一般右上角的三点)
- 右键res,新建menu类型资源文件夹
- 右键刚刚新建的menu文件夹,创建Menu资源文件
- 在menu资源文件xml中编写菜单栏项目,示例代码如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add"
android:title="添加"/>
<item
android:id="@+id/remove"
android:title="移除"/>
</menu>
- 重写onCreateOptionsMenu方法,通过getMenuInflater().inflate加载我们刚刚创建的menu资源,注意,最后要返回true才能显示我们的menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
- 此时运行程序,就可以看到右上角有三个点,点击就可以看到我们设置的菜单项
- 通过重写onOptionsItemSelected方法,为每个菜单项添加点击事件
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId())
{
case R.id.add:
Toast.makeText(this, "点击了add菜单项", Toast.LENGTH_SHORT).show();
break;
case R.id.remove:
Toast.makeText(this, "点击了remove菜单项", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
2.2.3 如何实现活动跳转
一个活动对应一个交互界面,而一个app往往包含很多个交互界面,因此如何实现从一个交互界面(活动)跳转到另一个交互界面呢?
- 方式一、显示Intent
从活动FirstActivity跳转到活动SecondActivity,使用显示Intent方式实现的示例代码如下
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
- 首先通过构造函数实例化Intent,构造函数第一个参数当前活动的上下文,第二个参数是你要跳转到活动的class对象。
- 其次调用startActivity方法实现活动之间的跳转。
- 方式二、隐示Intent
从活动FirstActivity跳转到活动SecondActivity,使用隐示Intent方式实现的示例代码如下
- 首先为SecondActivity在manifest文件中的 activity标签添加intent-filter标签
<activity
android:name=".SecondActivity"
android:launchMode="singleInstance"
android:label="这是第二个活动"
android:exported="false">
<intent-filter>
<!-- 当前活动可以响应的标签 -->
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MY_CATEGORY" />
</intent-filter>
</activity>
- 其次在实例化intent对象时,将action的name字符串传入构造函数,并通过addCategory方法将xml中配置的category全部一一对应的添加进去,最后调用startActivity实现活动的跳转。
Intent intent = new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("android.intent.category.DEFAULT");//DEFAULT可以省略
intent.addCategory("android.intent.category.MY_CATEGORY");
startActivity(intent);
显式Intent多方便呀,为啥要用隐式Intent呢?又要配置manifest,又要多写代码。
因为,使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。
比如我采用隐式Intent启动一个网页活动,示例代码如下:
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
比如我采用隐式Intent启动给10086打电话的界面,示例代码如下:
Intent intent=new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
2.2.5 如何实现向下一个活动传递数据
Intent的putExtra方法可以实现以键值对的形式将数据传递给下一个活动,如从FirstActivity传递数据到SecondActivity的示例代码如下:
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("key","第一个活动窗口数据");
startActivity(intent)
如从SecondActivity获取FirstActivity传递的数据的示例代码如下:
Intent intent = getIntent();
String key = intent.getStringExtra("key");
2.2.5 如何实现向上一个活动返回数据
如从活动FirstActivity跳转到活动SecondActivity,想要将SecondActivity处理好的数据返回给FirstActivity的示例代码如下:
- 采用startActivityForResult跳转活动
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);//第二个参数是请求码,用于标识回调数据的来源*/
- 通过setResult方法将数据返回给上一个活动FirstActivity
Intent intent=new Intent();
intent.putExtra("return_data","【onCreate】你好,我是第二个和活动");
setResult(RESULT_OK,intent);
- FirstActivity活动重写onActivityResult方法,获取SecondActivity返回的数据
//requestCode是FirstActivity传入的请求码:1,resultCode是SecondActivity传入的请求码:RESULT_OK,data是返回的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String return_data = data.getStringExtra("return_data");
Log.d(TAG, return_data);
}
break;
default:
break;
}
}
2.2.6 如何销毁一个活动
销毁一个活动非常简单,只需要在本活动调用 finish()方法即可。
2.3 活动的生命周期
2.3.1 返回栈
理解活动的生命周期,首先要明白活动的返回栈。因为多个活动是可以叠加的,用户只能看到最上面的活动,我们每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键,会销毁最上面的活动,这时下面的一个活动就会显示出来。很明显,活动的操作与数据结构中后进先出的“栈”极其吻合,而Android是使用任务来管理活动的,一个任务就是存放在栈里的活动的集合,这个栈就称为返回栈。
2.3.2 活动生命周期中的4种状态
- 运行状态
活动位于返回栈的栈顶时,这时活动就处于运行状态。系统一般不会回收处于运行状态的活动。 - 暂停状态
活动不再处于栈顶位置,但是仍然可见时,这时活动就进入了暂停状态。因为并不是每个活动都占满屏幕的,比如一个对话框形式的活动只会占用屏幕中间的部分,那么它后面的部分可见的活动就是处于暂停状态。系统一般不会回收暂停状态的活动,除非内存极其紧张的情况下。 - 停止状态
当活动不再处于栈顶位置,并且完全不可见时,就进入了停止状态。当其他地方需要内存时,系统可能会回收停止状态的活动。 - 销毁状态
当活动从返回栈中移除时后,就会变成销毁状态。系统会优先回收处于销毁状态额活动,从而保证手机内存充足。
从上面可以看出,这四种状态最大的区别是,系统回收这四种状态活动所占用内存的优先级不同,从高到低依次是:销毁状态,停止状态,暂停状态,运行状态。
2.3.3 活动生命周期内各个阶段的回调函数
活动的整个生命周期可以划分为三种生存期,如下图所示。
- onCreate():它会在活动第一次被创建的时候调用,该方法在 Activity 的整个生命周期中只应发生一次。可以在该方法中完成一些初始化操作,如加载布局,绑定事件等。
- onStart():这个方法在活动由不可见变为可见的时候调用。
- onResume():这个方法在活动准备好与用户进行交互的时候调用。此时的活动一定处于返回栈的栈顶,并且处于运行状态。
- onPause():这个方法在系统准备去启动或者恢复另一个活动的时候调用。通常会在这个方法中将一些消耗CPU的资源释放掉,以保存一些关键数据。
- onStop():这个放在活动完全不可见的时候调用。它和onPause的主要区别在于,如果启动的新活动是一个对话框式的活动 [1],那么onPause方法会得到执行,而onStop方法不会执行,因为对话框式的活动并不会占满整个屏幕,上一个活动仍然部分可见。
- onDestory():这个方法在活动销毁之前调用,之后活动的状态将会变为销毁状态。
- onRestart():这个方法在活动由停止状态变为运行状态之前调用。一般是用户按下返回键的时候,一个停止状态的活动就会变为运行状态。
[1] 小知识:如何设计一个对话框式的活动呢?
我们只需要在AndroidManifest.xml文件中对应活动的Activity标签中添加android:theme=“@android:style/Theme.Dialog” 属性即可。
示例:
<activity
android:name=".DialogActivity"
android:theme="@android:style/Theme.Dialog"/>
2.3.4 如果活动被系统回收了,还想保留活动的数据,该怎么办?
比如用户在活动A的基础上启动了活动B,那么活动A就会进入停止状态,而停止状态的活动很有可能因内存紧张被系统回收,导致用户从B返回A的时候,发现A活动上的原本输入的数据都没了(因为系统因内存不足回收掉A活动后,用户再返回活动A就要重写通过onCreate方法重新创建活动),这对于用户是不友好的。
因此Activity提供了onSaveInstanceState()回调方法,该方法保证活动被回收之前一定被调用,因此,用户可以在该方法中保存一些避免因活动被系统回收而导致丢失的必要数据。onSaveInstanceState方法传入的参数带有一个Bundle类型的参数,用户可以通过Bundle数据结构保存数据,然后这个Bundle数据会被传入在onCreate()方法中,用户可以在onCreate中获取Bundle中保存的数据。
//系统回收活动前调用该方法
protected void onSaveInstanceState(@NonNull Bundle outState) {//...}
//活动创建时调用该方法,savedInstanceState是由outState传入
protected void onCreate(Bundle savedInstanceState) {//...}
2.4 活动的启动模式
活动的启动模式一共有四种,可以通过< Activity >标签指定android:launchMode属性选择启动模式。
android:launchMode=["standard" | "singleTop" |
"singleTask" | "singleInstance" | "singleInstancePerTask"]
2.4.1 standard
standard模式是活动的默认启动模式。使用standard模式启动的活动,系统不管这个活动是否已经存着返回栈中,每次启动都会创建一个新的活动实例。
2.4.2 singleTop
使用singleTop模式启动活动,系统会先判断返回栈的栈顶是否存着该活动,若存在,则直接使用栈顶的活动,不会再创建新的活动实例。如果活动存在,但并不在返回栈的栈顶,系统仍然会创建新的活动实例。
2.4.3 singleTask
singleTop模式可以解决重复创建返回栈栈顶活动的问题,但如果活动没有处在栈顶位置,还是会出现重复创建的问题,那么singleTask模式就可以保证某个活动在整个应用程序中只存在一个实例。
使用singleTask模式启动的活动,系统会首先在返回栈中查找是否已经存在该活动,若存在,则使用该活动,并把返回栈中该活动之上的所有活动全部出栈;若不存在,则创建一个新的活动实例。
2.4.4 singleInstance
使用singleInstance模式启动的活动,会在一个新的返回栈中管理该活动。
如我们设计FirstActivity、SecondActivity、ThirdActivity三个活动,并将SecondActivity设置为singleInstance启动模式,我们首先从FirstActivity中启动SecondActivity活动,然后从SecondActivity中启动ThirdActivity活动,返回栈示意图如下。SecondActivity会启用一个单独的返回栈管理该活动,当用户点返回键会直接回到FirstActivity,然后再点击返回键,才会回到SecondActivity。
2.5 使用活动的小技巧
我们可以设计一个活动基类,并在这个基类的onCreate方法中打印类名,也可以在这个方法中收集活动实例,在onDestory方法中移除活动实例。然后其它活动都继承这个基类活动,这样我们就能获取当前活动的类名,并且收集所有现存活动的实例,以便在任何位置关闭所有活动实现程序退出,而不必一次次点击back键。
示例代码:
public class BaseActivity extends AppCompatActivity {
private static final String TAG = "BaseActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, getClass().getSimpleName());//打印活动名
ActivityCollector.addActivity(this);//收集启动的活动实例
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);//移除销毁的活动实例
}
}
参考书籍:第一行代码
链接:https://pan.baidu.com/s/1aXtOQCXL6qzxEFLBlqXs1Q?pwd=n5ag
提取码:n5ag