[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>
```

* 當然你可以可以通過設置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()方法去銷毀一個活動時,棧頂元活動會出棧。

### 5.2 活動狀態
* 運行狀態
當活動位于返回棧棧頂時。
* 暫停狀態
當活動不在棧頂的,但仍然可見時,例如打開一個對話框時(對話框并不占滿整個屏幕),對話框背后的活動就是暫停狀態.
* 停止狀態
活動不在棧頂,并且完全不可見.
* 銷毀狀態
當活動從棧中移除.
### 5.3 活動的生命周期
* onCreate() 創建
* onStart() 不可見 to 可見
* onResume() 活動位于棧頂,馬上就要與用戶進行交互了.
* onPause() 準備啟動或者恢復另一個活動.
* onStop() 可見 to 不可見(不在棧頂,并完全不可見)
* onDestroy() 銷毀
* onRestart() 停止 to 運行
* 除了onRestart()上面方法涼涼相對
* 完整生命周期,onCreate() to onDestroy()
* 可見生命周期,onStart() to onStop()
* 前臺生命周期,onResume() to onPause()

### 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在返回棧中是否已經存在.

* singleTop
當活動A已經位于棧頂時,不會再創建A活動,當其他活動B位于棧頂時可以創建A活動。

* singleTask
當活動A再返回棧中已經存在,但是活動A并不位于棧頂,此時再創建活動A時,不會創建真正的實例,而是會從返回棧中喚醒A活動放到棧頂.

* 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());
}
}
```
