[TOC]
## 一、什么是活动
Android四大组件之一,用于与用户之间进行交互,你在Android上所看到的可以交互的程序界面都属于活动.
## 二、活动的创建
创建活动一般需要2个步骤:
* 创建活动类继承自`AppCompatActivity`.
* 在AndroidManifest.xml文件中进行注册.
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--注册活动name = .活动类名-->
<activity android:name=".FirstActivity"></activity>
<activity android:name="..."></activity>
</application>
</manifest>
```
## 三、主活动
什么是主活动?就是你打开Android程序后第一个看到的界面,同样在AndroidManifest.xml文件中进行设置.
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--注册活动-->
<!--label中设置活动标题-->
<!--android.intent.action.MAIN" "android.intent.category.LAUNCHER"表示设置为主活动-->
<activity android:name=".FirstActivity"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
```
## 四、在活动间穿梭
**Intent**(中文翻译为'意图')是Android程序中各组件之间进行交互的一种重要方式.
### 4.1 显式Intent
从FirstActivity跳转到SecondActivity.
```java
//public Intent(Context packageContext, Class<?> cls)
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
```
### 4.2 隐式Intent
* 在AndroidManifest.xml文件中为Activity注册action和category信息.
* 通过intent发送action和category,当系统检测到某个activity匹配到相同的action和category时就会启动该Activity.
**Demo1** 自定义action+系统缺省category.
```
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
```
```java
button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
});
```
**Demo2** 自定义action+自定义category.
```
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<!--实验证明android.intent.category.DEFAULT这条必须得有否则会崩溃.-->
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>
```
```java
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
}
});
```
PS:细心的朋友可以发现,Android程序的主活动其实就是通过隐式Intent实现的.
### 4.3 更多隐式的Intent的用法
* 如何打开一个指定网址的Activity页面.
```java
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
```
可以看到我们这里是通过匹配action和data来匹配到合适的Activity的(Uri.parse("http://www.baidu.com")会把一个网址解析为Uri对象).
* data标签的配置.
|配置内容|解释|
|-|-|
|android:scheme|指定数据的协议部分,例如http|
|android:host|指定数据的主机部分,例如www.baidu.com|
|android:port|指定数据的端口部分|
|android:path|指定域名之后的内容|
|android:miniType|指定可以处理的数据类型|
* 自定义一个可以响应data中scheme部分为http的activity.
```xml
<activity android:name=".ThridActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
```
![](https://box.kancloud.cn/144977f1e17e136a0f1be1f84ff805c8_526x833.png)
* 当然你可以可以通过设置data打开其他内置activiy(如通讯录)
```java
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
```
### 4.4 向下一个活动传递数据
既然Intent能完成一个activity到另一个activity的跳转,那么它必然也会具备跳转时传输数据的能力.
通过跳转时为intent附加上键值对的方式进行数据传输.
```java
// FirstActivity
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("extra_data",data);
startActivity(intent);
```
```java
//SecondActivity
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity",data);
```
### 4.5 返回数据给上一个活动
在4.4 小节中数据传递是从FirstActivity到SecondActivity,如果我们希望数据从SecondActivity-FirstActivity呢?
* FirstActivity跳转时调用startActivityForResult方法.
* FirstActivity覆盖onActivityResult方法监听返回结果.
* SecondActivity创建intent通过setResult进行传递.
```java
// FirstActivity
public class FirstActivity extends AppCompatActivity {
public Button button1 = null;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// requestCode为请求码,与startActivityForResult(intent,1)第二个参数对应.
switch (requestCode)
{
case 1:
if (resultCode == RESULT_OK){
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity",returnedData);
}
break;
default:
break;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
// 第二个参数1表示请码,可以自己定义.
startActivityForResult(intent,1);
}
});
}
}
```
```java
//SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK,intent);
finish();
}
}
```
上面代码会在跳转到SecondActivity时马上返回FirstActivity,我们也可以把返回数据的工作放到点击手机的返回按键时进行.
```java
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
}
@Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK,intent);
finish();
}
}
```
## 五、 活动的生命周期
### 5.1 活动的管理方式
* 任务(Task):Android使用任务来管理活动.
* 返回栈(Back Stack):一个任务就是存放在栈里活动的集合,这个栈称为返回栈.
* 当按下back按键或者调用finish()方法去销毁一个活动时,栈顶元活动会出栈。
![](https://box.kancloud.cn/dedc16a30cf79c4013e788397c4e496e_543x366.png)
### 5.2 活动状态
* 运行状态
当活动位于返回栈栈顶时。
* 暂停状态
当活动不在栈顶的,但仍然可见时,例如打开一个对话框时(对话框并不占满整个屏幕),对话框背后的活动就是暂停状态.
* 停止状态
活动不在栈顶,并且完全不可见.
* 销毁状态
当活动从栈中移除.
### 5.3 活动的生命周期
* onCreate() 创建
* onStart() 不可见 to 可见
* onResume() 活动位于栈顶,马上就要与用户进行交互了.
* onPause() 准备启动或者恢复另一个活动.
* onStop() 可见 to 不可见(不在栈顶,并完全不可见)
* onDestroy() 销毁
* onRestart() 停止 to 运行
* 除了onRestart()上面方法凉凉相对
* 完整生命周期,onCreate() to onDestroy()
* 可见生命周期,onStart() to onStop()
* 前台生命周期,onResume() to onPause()
![](https://box.kancloud.cn/c0cc434d86651592fef1025329169ae6_761x988.png)
### 5.4 活动被系统自动回收了怎么办
一个活动进入了停止状态后是可能被系统回收的,但如果这个活动中保存了临时数据我们不想它被回收怎么办,那就需要在系统要回收资源的时候将临时数据保存起来,等该活动再创建时将数据再回复出来.
* 重载onSaveInstanceState,将临时数据保存到Bundle对象的键值对中.
* 在onCreate函数中从Bundle对象中取出数据.
```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
if (savedInstanceState!=null){
String tempData = savedInstanceState.getString("data_key");
Log.d("tag",tempData);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Someteing you just typed";
outState.putString("data_key",tempData);
}
```
### 5.5 活动的启动模式
1. 如何设置Activity的启动模式?
在AndroidManifest.xml中设置activity标签的android:launchMode属性来实现.
2. 活动模式的种类.
* standard
默认活动的启动模式,每当启动活动A时都会创建一个新的活动A放到栈顶,不管活动A在返回栈中是否已经存在.
![](https://box.kancloud.cn/d8885c8ee24e90fb61112ed393d19b57_440x257.png)
* singleTop
当活动A已经位于栈顶时,不会再创建A活动,当其他活动B位于栈顶时可以创建A活动。
![](https://box.kancloud.cn/2a4c6d246f11376d81b6d0bf1351336c_509x263.png)
* singleTask
当活动A再返回栈中已经存在,但是活动A并不位于栈顶,此时再创建活动A时,不会创建真正的实例,而是会从返回栈中唤醒A活动放到栈顶.
![](https://box.kancloud.cn/10bdba3b7ad56934deb9ef08d30a2c99_419x267.png)
* singleInstance
每个Android程序都会有自己返回栈来管理活动,但是使用singleInstance启动模式的活动在启动时会被放到一个新的返回栈中,并且这个新的返回栈是所有Android程序中使用了singleInstance作为启动模式的活动所共用的.
例:有三个Activity FirstActivity SecondActivity ThirdActivity,将SecondActivity的启动模式设置为singleInstance,其它默认,我们让三个Activity依次启动并在三个Activity中分别打印下返回栈的TaskId,你会发现FirstActivity和ThirdActivity的TaskId是相同的,SecondActivity有自己的TaskId.
如果你连续按下返回键你会发现Activity回退的顺序是ThirdActivity FirstActivity SecondActivity,因为ThirdActivity与FirstActivity是在一个返回栈中的.
```xml
<!--AndroidManifest.xml-->
<activity android:name=".SecondActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>
```
```java
//FirstActivity
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Log.d("FirstActivity","Task id is "+getTaskId());
Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);
}
});
}
}
```
```java
//SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
Log.d("SecondActivity","Task id is "+getTaskId());
Button button2 = (Button)findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent intent = new Intent(SecondActivity.this,ThridActivity.class);
startActivity(intent);
}
});
}
}
```
```java
//ThirdActivity
public class ThirdActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thrid_layout);
Log.d("ThirdActivity","Task id is "+getTaskId());
}
}
```
![](https://box.kancloud.cn/42880f76db678f90be94b325ec8c8dca_551x256.png)