本文讲解Android四大组件之一(活动)的基本用法,生命周期,启动模式等。
活动是一种包含用户界面的组件,主要用于和用户进行交互。简单来说,一个活动就对应一个交互窗口。
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活动的程序中弹出一条信息提示。
<?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>
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
@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;
}
一个活动对应一个交互界面,而一个app往往包含很多个交互界面,因此如何实现从一个交互界面(活动)跳转到另一个交互界面呢?
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
<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 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);
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");
如从活动FirstActivity跳转到活动SecondActivity,想要将SecondActivity处理好的数据返回给FirstActivity的示例代码如下:
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);//第二个参数是请求码,用于标识回调数据的来源*/
Intent intent=new Intent();
intent.putExtra("return_data","【onCreate】你好,我是第二个和活动");
setResult(RESULT_OK,intent);
//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;
}
}
销毁一个活动非常简单,只需要在本活动调用 finish()方法即可。
理解活动的生命周期,首先要明白活动的返回栈。因为多个活动是可以叠加的,用户只能看到最上面的活动,我们每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键,会销毁最上面的活动,这时下面的一个活动就会显示出来。很明显,活动的操作与数据结构中后进先出的“栈”极其吻合,而Android是使用任务来管理活动的,一个任务就是存放在栈里的活动的集合,这个栈就称为返回栈。
从上面可以看出,这四种状态最大的区别是,系统回收这四种状态活动所占用内存的优先级不同,从高到低依次是:销毁状态,停止状态,暂停状态,运行状态。
活动的整个生命周期可以划分为三种生存期,如下图所示。
[1] 小知识:如何设计一个对话框式的活动呢?
我们只需要在AndroidManifest.xml文件中对应活动的Activity标签中添加android:theme=“@android:style/Theme.Dialog” 属性即可。
示例:
<activity
android:name=".DialogActivity"
android:theme="@android:style/Theme.Dialog"/>
比如用户在活动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) {//...}
活动的启动模式一共有四种,可以通过< Activity >标签指定android:launchMode属性选择启动模式。
android:launchMode=["standard" | "singleTop" |
"singleTask" | "singleInstance" | "singleInstancePerTask"]
standard模式是活动的默认启动模式。使用standard模式启动的活动,系统不管这个活动是否已经存着返回栈中,每次启动都会创建一个新的活动实例。
使用singleTop模式启动活动,系统会先判断返回栈的栈顶是否存着该活动,若存在,则直接使用栈顶的活动,不会再创建新的活动实例。如果活动存在,但并不在返回栈的栈顶,系统仍然会创建新的活动实例。
singleTop模式可以解决重复创建返回栈栈顶活动的问题,但如果活动没有处在栈顶位置,还是会出现重复创建的问题,那么singleTask模式就可以保证某个活动在整个应用程序中只存在一个实例。
使用singleTask模式启动的活动,系统会首先在返回栈中查找是否已经存在该活动,若存在,则使用该活动,并把返回栈中该活动之上的所有活动全部出栈;若不存在,则创建一个新的活动实例。
使用singleInstance模式启动的活动,会在一个新的返回栈中管理该活动。
如我们设计FirstActivity、SecondActivity、ThirdActivity三个活动,并将SecondActivity设置为singleInstance启动模式,我们首先从FirstActivity中启动SecondActivity活动,然后从SecondActivity中启动ThirdActivity活动,返回栈示意图如下。SecondActivity会启用一个单独的返回栈管理该活动,当用户点返回键会直接回到FirstActivity,然后再点击返回键,才会回到SecondActivity。
我们可以设计一个活动基类,并在这个基类的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