在 Android 开发过程中,与程序员打交道最多的应该就是作为四大组件之一的 Activity 了。接下来我们就一起来揭开 Activity 的神秘面纱吧~
一、概述
什么是 Activity(活动)?当用户打开一个软件,首先看到的就是各种界面,这些界面就是 Activity。
二、使用 Intent 在 Activity 之间穿梭
一个程序不可能只有一个 Activity,在使用软件过程中必然会产生界面的跳转,这就涉及到 Activity 的转换。在 Android 开发中,开发者可以使用 Intent 在不同 Activity 之间跳转。
显式跳转
使用显示 Intent 进行跳转非常简单,只需在代码中创建一个 Intent 对象,调用 Intent() 方法即可。
示例:Intent intent = new Intent(ThisActivity.this,AnotherActivity.class);
startActivity(intent);
隐式跳转
使用隐式跳转则比较复杂,首先需要在 AndroidManifest.xml 文件内进行配置。每个 <activity> 标签内部都可以进行 <intent-filter> 标签的设置,在这个标签内部有两个标签:<action>、<category>
为这两个标签设置参数,然后在逻辑代码中进行匹配,即可跳转到指定的 Activity。
示例:首先配置两个标签内参数 <action android:name = "com.example.activitytest.ACTION_START" />
<category android:name = "android.intent.category.DEFAULT" />
<category android:name = "com.example.activitytest.MY_CATEGORY" /> ps:<category> 标签可以有多个,在进行匹配时可以灵活应用。
随后在逻辑代码中进行匹配 Intent intent = new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
在使用隐式跳转的时候,<action>标签内的参数可以设置成调用系统浏览器、电话拨号盘等系统内置应用。最主要的优势在于你的程序中某个 Activity 是允许另外一个程序进行访问的,如支付宝的支付接口。
那么使用显示跳转显然是做不到的,这时候就需要配合 Activity 的启动模式以及隐式跳转就可以实现。
带数据跳转
使用 Intent 进行界面跳转的时候,其实可以通过 Intent 的 putExtra() 等方法进行数据的传递。如当前活动需要向下一个活动传递一个字符串,那么就可以这样实现:
在当前活动中:String data = "Hello NextActivity";
Intent intent = new Intent(ThisActivity.this,NextActivity.class); //使用显式跳转
intent.putExtra("extra_data",data); //putExtra()方法传递参数以键值对形式进行传送
startActivity(intent);
在下一个活动中:Intent intent = getIntent();
String data = intent.getStringExtra("extra_data"); //不同数据类型对应不同方法,getIntExtra()、getBooleanExtra()等
回传数据
其实当一个活动销毁的时候也能够返回数据给上一个活动,比如第三方登录接口,当软件通过微信进行授权登录时,会跳转的一个微信的授权界面,点击授权后返回登录界面发现登录成功了。
这时授权界面销毁后就回传了一些数据给登录界面使得用户登录成功。
在Activity中有一个startActivityForResult()的方法,这个方法有两个参数,一个依旧是Intent对象,另一个是请求码。
首先在FirstActivity中:Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityFroResult(intent,1); //此方法内第二个参数是请求码,当下一个活动回传数据时会根据这个参数判断回传给哪一个活动
其次在SecondActivity中:Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK,intent); //返回数据给上一个活动的方法,第一个参数是处理结果,第二个是带有数据的 Intent 对象
finish(); //销毁当前活动
最后由于是使用startActivityFroResult()方法启动的SecondActivity,所以当SecondActivity销毁时会回调上一个活动的onActivityResult()方法,我们需要重写这个方法来接收数据。
在FirstActivity中:@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
//此方法内第一个参数就是startActivityFroResult()方法内第二个参数,此方法第二个参数就是setResult()方法内的第一个参数,此方法第三个参数就是setResult()方法内的第二个参数
{
switch(requestCode)
{
case 1:
if (resultCode == RESULT_OK)
{
String returnData = data.getStringExtra("data_retuen");
}
break;
}
}
三、生命周期
在 Android 中是使用 Task(任务)来管理活动的,任务是一组放在栈里的集合,这个栈也叫作返回栈(Back Stack)。
当活动被创建显示给用户时,活动会入栈并置于栈顶,系统总是将栈顶的活动显示给用户。当一个活动不在需要显示给用户时就会出栈或者被其他活动压如栈底。活动的出入栈遵循先进后出原则。
一个 Activity 拥有4种状态7种回调方法,灵活应用 Activity 的生命周期能使程序运行更顺畅,更合理利用程序资源内存。
7种回调方法分别是 onCreat()、onStart()、onResume()、onPause()、onStop()、onDestory()、onRestart()。
这7种方法中除了onRestart() 其他6种都是两两对应的。
完整生存期
活动在 onCreat() 到 onDestory() 之间经历就是一个完整生存期。一般会在 onCreat() 进行各种初始化操作,在 onDestory() 中进行释放内存操作。
可见生存期
活动在 onStart() 到 onStop() 之间经历的就是一个可见生存期。在这期间活动对于用户总是可见的,但不一定可以进行交互。一般可以在 onStart() 中对资源进行加载,在 onStop() 中释放资源。
前台生存期
活动在 onResume() 到 onPause() 之间经历的就是一个前台生存期。在这期间活动总是运行状态,平时接触最多的就是这种状态下的活动。
运行状态
当活动位于返回栈的栈顶时,就处于运行状态,此时活动对于用户是可见可交互状态。系统最不愿意回收的就是这种状态的活动,会带来非常差的体验,就好比程序突然崩溃一样。
暂停状态
当活动不处于栈顶但对于用户依然可见时,就处于暂停状态,此时活动对于用户可见但不可交互,如被弹框遮挡部分时。系统也不愿意回收这样的活动,只有在内存极低情况下系统才考虑回收这种活动。
停止状态
当活动不处于栈顶且对于用户完全不可见时,就处于停止状态,此时系统仍然会为活动保留相应状态和成员变量,但是其他地方需要内存时,活动可能会被系统回收。
销毁状态
当活动从返回栈中出栈后,就处于销毁状态,系统最喜欢回收这样的活动,保证系统内存充足。
这张图详细说明了活动的生命周期。
四、启动模式
活动有四种启动模式:standard、singleTop、singleTask、singleInstance。
在 AndroidManifest.xml 文件中可以对活动设置启动模式:<activity android:name=".SecondActivity" android:launchMode="singleInstance" />
默认模式 standard
没有指定启动模式的活动都是默认指定为 standard 启动模式。
在次模式下,每当启动一个活动时,就会在返回栈顶创建一个该活动的实例,这样会导致同一个活动被重复创建多次。
栈顶模式 singleTop
在该模式下,每当启动一个活动时,系统会判断返回栈顶的活动是不是该活动,如果是则直接调用,如果不是则重新创建。
如:现在栈顶的活动是FirstActivity,在FirstActivity中启动SecondActivity,此时栈顶的活动是SecondActivity,然后在SecondActivity启动FirstActivity;由于FirstActivity未处于栈顶,系统在栈顶重新创建了一个FirstActivity。
这样会导致之前第一个创建的FirstActivity上的数据丢失,因为用户可能在第一个FirstActivity上输入了一些文字,但是第二次的FirstActivity是新创建的,并没有用户输入的文字。
返回栈模式singleTask
在该模式下,每当启动一个活动时,系统会在整个返回栈内搜索判断有没有这个活动,如果有则直接调用,没有就创建一个放在栈顶。
开小灶模式singleInstance
若是一个活动被设置为这种启动模式,系统会为活动单独开辟一个返回栈进行管理,此时的活动是可以被其他程序进行访问的。
我的GitHub内有Demo对活动的启动模式和生命周期进行展示:点我点我!
五、关于 Intent 带数据跳转的"BUG"
不论是使用 Intent 向下一个活动传递数据还是回传数据给上一个活动,对活动的启动模式都要要求。
我在测试的时候发现,活动的启动模式设为 singleTask 和 singleInstance 的时候,数据的传递会在某些情况下失效。
具体原因还没有研究明白,不过 standard 和 singleTop 模式是没有任何问题的。