一、Activity簡介
- Activity是四大組件之一,用於表現功能。
- 一個Activity通常就是一個單獨的屏幕(窗口)。
- Activity之間通過Intent進行通信。
- android應用中每一個Activity都必須要在AndroidManifest.xml配置文件中聲明,否則系統將不識別也不執行該Activity。
二、創建一個Activity
- 自定義類繼承系統Activity
- 複寫Activity中Onreate方法
- 在佈局文件夾中書寫相應的佈局文件
- 調用setContent(R.layout.activity_main)
//參數爲佈局文件中的相應的文件名 - 在AndroidManifest.xml註冊Activity
否則報:ActivityNotFoundException
public class BActivity extends Activity {
/**
* 複寫Activity中Onreate方法
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);// 調用setContentView方法
}
}
// 佈局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</LinearLayout>
// Activity組件註冊,一律在<application></application>根標籤中進行
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<!--
此處<intent-filter></intent-filter>聲明,默認首次打開MainActivity界面
可將此代碼複製到MyActivity的聲明中,則表明首次打開MyActivity界面
-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
android:name 包名全路徑 + 類名
如果需要註冊的Activity在pagegeName文件夾中,則不需要指定包名
-->
<activity android:name=".BActivity" >
<intent-filter>
<action android:name="com.vince.day06.b"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="com.vince.utils.CActivity" >
<intent-filter>
<action android:name="com.vince.day06.c"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
三、啓動/跳轉一個Activity
1. 顯示跳轉:指出具體跳轉的Activity名稱
/**
* 源Activity
*
* @param view
*/
public void startB(View view) {
// 創建Intent意圖對象,指定要跳轉到的界面--BActivity.class
Intent intent = new Intent(this, BActivity.class);
// 通過putExtra()方法,設置傳遞值
intent.putExtra("key", "啓動B成功!");
// 啓動
startActivity(intent);
}
// 目標Activity
Intent newIntent = getIntent();// 獲取啓動BActivity的intent對象
String content = newIntent.getstringExtra("key");// 獲取對象中的信息
2. 隱式跳轉:系統根據action和category計算出跳轉哪個界面
2.1 第一種情況:A傳值—–>B接收
/**
* 源Activity
*
* @param view
*/
public void startB(View view) {
// 創建Intent意圖對象
Intent intent = new Intent();
// 設置action、category
intent.setAction("com.vince.day06.b");
// intent.addCategory(Intent.CATEGORY_DEFAULT); 默認添加
// 通過putExtra()方法,設置傳遞值
intent.putExtra("intkey", 20);
// 啓動
startActivity(intent);
}
// 目標Activity
Intent newIntent = getIntent();// 獲取啓動BActivity的intent對象
String content = newIntent.getstringExtra("intkey");// 獲取對象中的信息
2.2 第二種情況:A傳值—–>B接收,B返值—–>A接收
/**
* 源Activity
*
* @param view
*/
public void startC(View view) {
// 創建Intent意圖對象
Intent intent = new Intent();
// 設置action、category
intent.setAction("com.vince.day06.c");
// 通過putExtra()方法,設置傳遞值
intent.putExtra("intkey", 15);
// 啓動(請求碼可隨意取,此處取10)
startActivityForResult(intent, 10);
}
/**
* 重寫onActivityResult(int requestCode, int resultCode, Intent data)方法
*
* @param requestCode
* :請求碼
* @param resultCode
* :是在目標Activity調用setResult時返回的結果碼
* @param data
* :是在目標Activity調用setResult時傳入返回的對象
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data != null) {
Toast.makeText(this, "返回值爲" + data.getStringExtra("return"), 1000).show();
}
}
// 目標Activity
Intent intent = getIntent();// 獲取啓動CActivity的intent對象
int a = intent.getIntExtra("intkey", -1);// 獲取對象中的信息
if (a != -1) {
Toast.makeText(this, "接收MainActivity傳遞過來的值爲" + a, 2000).show();
}
// 新建一個Intent意圖對象,用於返回值
Intent newIntent = new Intent();
// 通過putExtra()方法,設置返回值
newIntent.putExtra("return", "接收成功!");
setResult(2, newIntent);// 參數中,結果碼2可以隨意取
// 結束CActivity
finish();
注意:如果有多個Activity註冊同樣的intent-filter(即action和category相同),在啓動Activity時,則會彈出多個選擇框,提供給用戶自主選擇
四、Activity生命週期
生命週期流程圖如下:
1. Activity一生中有七種不同狀態
(1)onCreate()
(2)onStart()
(3)onResume()
(4)onPause()
(5)onStop()
(6)onRestart()
(7)onDestroy()
package com.danny_jiang.day06_lifecycle;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
private int progress;
/**
* 創建一個新的Activity實例時,此方法被調用
*
* @param savedInstanceState
* 當第一次創建Activity時,此實例爲null 只有當Activity發生配置改變,或者被異常殺死時
* 此參數纔有具體的實現
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("TAGA", "onCreate---" + savedInstanceState);
if (savedInstanceState != null) { // 說明之前發生過配置改變
int savedProgress = savedInstanceState.getInt("progress");
progress = savedProgress;
}
}
/**
* 當點擊Button按鈕時,動態的修改模擬播放進度
*
* @param view
*/
public void progress(View view) {
Toast.makeText(this, "播放到了 " + progress++, 1000).show();
}
/**
* 當Activity發生配置改變,或者被異常殺死時,此方法會被自動調用
* 一般在此方法中做數據的保存工作,重新打開Activity時,可以取出保存的數據
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// 將當前的progress值保存到outState Bundle對象中
// 當onCreate被重新調用時,可以從此Bundle中取出progress值
outState.putInt("progress", progress);
}
/**
* 當一個Activity由不可見狀態改爲可見狀態時,此方法會被調用
*/
@Override
protected void onRestart() {
super.onRestart();
Log.e("TAGA", "onRestart");
}
/**
* 當調用到此方法後,Activity會被顯示到屏幕上
* 注意:Activity並不會獲取焦點
*/
@Override
protected void onStart() {
super.onStart();
Log.e("TAGA", "onStart");
}
/**
* Activity獲取焦點,用戶可以與之進行交互
*/
@Override
protected void onResume() {
super.onResume();
Log.e("TAGA", "onResume");
}
/**
* Activity失去焦點,但是Activity還是顯示在屏幕上
*/
@Override
protected void onPause() {
super.onPause();
Log.e("TAGA", "onPause");
}
/**
* Activity從屏幕上消失
*/
@Override
protected void onStop() {
super.onStop();
Log.e("TAGA", "onStop");
}
/**
* Activity實例被銷燬,Activity聲明週期結束
*/
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("TAGA", "onDestroy");
}
public void btnClick(View view) {
startActivity(new Intent(this, BActivity.class));
}
}
2. 典型的幾種操作分析:
2.1 打開一個應用,然後點擊back鍵退出:
onCreate()--->onStart()--->onResume()---按back鍵--->onPause()--->onStop()--->onDestroy()
2.2 打開一個應用,然後點擊home鍵退出,再重新打開應用:
onCreate()--->onStart()--->onResume()---點擊home鍵--->onPause()---onStop()---重新打開應用--->onRestart()--->onStart()---onResume()
2.3 打開一個Activity,點擊該Activity上的按鈕跳轉到SecondActivity:
M-onCreate()--->M-onStart()--->M-onResume()---點擊跳轉按鈕---M-onPause()-->S-onCreate()--->S-onStart()--->S-Resume()--->M-onStop()
2.4 打開一個Activity,點擊該Activity上的按鈕跳轉到SecondActivity,然後點擊back鍵退出SecondActivity:
M-onCreate()--->M-onStart()--->M-onResume()---點擊跳轉按鈕--->M-onPause()-->S-onCreate()--->S-onStart()--->S-Resume()--->M-onStop()
---點擊back鍵退出SecondActivity--->S-onPause()-->M-onRestart()--->M-onStart()--->M-onResume()--->S-onStop()--->S-onDestroy()
2.5 打開一個Activity,然後從豎屏切換爲橫屏
onCreate()--->onStart()--->onResume()--切換爲橫屏-->onPause()--->onStop()--->onDestroy()--->onCreate()--->onStart()--->onResume()
2.6 打開一個Activity,然後從豎屏切換爲橫屏(onSaveInstanceState,onRestoreInstanceState):
onCreate()--->onStart()--->onResume()---切換爲橫屏--->onSaveInstanceState()--->onPause()--->>onStop()--->onDestroy()--->onCreate()
--->onStart()--->onRestoreInstanceState()--->onResume()
2.7 打開一個Activity,點擊該Activity上的按鈕跳轉到ThirdActivity(ThirdActivity主題爲Dialog模式),然後點擊back鍵:
M-onCreate()--->M-onStart()--->M-onResume()--點擊跳轉按鈕-->M-onPause()--->T-onCreate()--->T--->onStart()--->T-onResume()
--點擊back鍵-->T-onPause()--->M-onResume()--->T-onStop()--->T-onDestroy()
2.8 打開一個Activity,然後從豎屏切換爲橫屏(配置android:configChanges="orientation|screenSize")
onCreate()--->onStart()--->onResume()---切換橫屏--->onConfigurationChanged()
備註:
A、七個生命週期組合:
啓動應用程序:onCreate、onStart、onResume
失去焦點:onPause、onStop
重新獲得焦點:onRestart、onStart、onResume
退出應用程序:onPause、onStop、onDestroy
B、七個生命週期按階段劃分:
完整生命週期(The entire lifetime):onCreate() --- onDestroy()
可見生命週期(The visible lifetime):onStart() --- onStop()
前沿生命週期(焦點生命週期The foreground lifetime):onResume() --- onPause()
3. 生命週期的作用
① 當用戶接到一個電話或切換到另一個程序時不會崩潰
② 當用戶後臺運行程序時,不會銷燬有價值的系統資源
③ 當用戶離開再返回某應用時,不會丟失用戶的進程
④ 當手機屏幕進行橫豎屏切換時,不會崩潰或者丟掉用戶的進程
五、Activity啓動模式
1. 任務
1.1 概念
一個任務(task)就是在執行某項工作時與用戶進行交互的Activity的集合。
這些Activity按照被打開的順序依次被安排在一個堆棧中(回退棧)。
1.2 主屏頁面
設備的主屏是大多數任務的啓動位置,當用戶觸摸一個應用程序啓動器圖標(或者app快捷圖標),應用程序的任務就會在前臺顯示。
如果相關應用程序的任務不存在,那麼就會有一個新的任務被創建,並且應用程序打開的“主”Activity會作爲任務中的根Activity。
2. 回退棧
1.1 概念
在當前的Activity啓動了另一個Activity時,這個新的Activity被放到了堆棧的頂部,並且帶有焦點。前一個Activity並沒有消失,
而是保存在回退棧中,此時它處於停止狀態。
當用戶按下回退按鈕時,當前的Activity會被從回退棧的頂部彈出(被銷燬),而前一個Activity被恢復。
如果用戶繼續按回退按鈕,那麼回退棧中的每個Activity會被依次彈出,前一個Activity會被顯示,直到用戶返回主屏(或者返回到任務開始時運行
的那個Activity)。當所有的Activity從回退棧中被刪除時,這個任務就不再存在了。
**注意:堆棧中的Activity不會被重新排列。因此,回退棧的操作跟後進先出的對象結構是一樣的。**
3. Activity啓動模式
在Android中每個界面都是一個Activity,切換界面操作其實是多個不同Activity之間的實例化操作。
在Android中Activity的啓動模式決定了Activity的啓動運行方式。
3.1 Activity啓動模式設置(AndroidManifest.xml配置文件):
<activity android:name=".BActivity"
android:launchMode="standard">
</activity>
<activity android:name=".CActivity"
android:launchMode="singleTop">
</activity>
<activity android:name=".DActivity"
android:launchMode="singleTask">
</activity>
<activity android:name=".EActivity"
android:launchMode="singleInstance">
</activity>
3.2 Activity的四種啓動模式:
A.standard(系統默認):
每次激活Activity時都會創建Activity,並放入任務棧中。
每個窗體的getTaskId()保持不變,但是this.hashCode()發生改變。
B.singleTop:
如果在任務的棧頂正好存在該Activity的實例,就重用該實例,而不會創建新的Activity對象,不過它會調用
onNewIntent()方法。
如果棧頂部不存在就會創建新的實例並放入棧頂(即使棧中已經存在該Activity實例,只要不在棧頂,都會創建
實例),會回調onNewIntent()方法。
C.singleTask:
如果在棧中已有該Activity的實例,就重用該實例(調用實例的onNewIntent())。重用時,會讓該實例回到
棧頂。因此,在它上面的實例將會被移除棧。
如果棧中不存在該實例,將會創建新的實例放入棧中。
singleTop每次只檢測當前棧頂的Activity是否是我們需要請求創建的,而singleTask則會檢測棧中全部的
Activity對象,從上向下,如果檢測到是我們所請求的則會消滅此Activity對象上面的對象,直接把檢測到的我們需
要的Activity置爲棧頂。
D.singleInstance:
與singleTask模式的區別是存放singleInstance模式窗口對象的回退棧不能有其他任何窗口對象。因此如果
該窗口不存在,則要新建任務來存放該singleInstance模式窗口。
也就是說getTaskId()會發現任務id發生了變化。此啓動模式和我們使用的瀏覽器工作原理類似,在多個程序中
訪問瀏覽器時,如果當前瀏覽器沒有打開,則打開瀏覽器,否則會在當前打開的瀏覽器中訪問。
此模式會節省大量的系統資源,因爲它能保證要請求的Activity對象在當前的棧中只存在一個。