Android四大組件之一——Activity

一、Activity簡介

  1. Activity是四大組件之一,用於表現功能。
  2. 一個Activity通常就是一個單獨的屏幕(窗口)。
  3. Activity之間通過Intent進行通信。
  4. android應用中每一個Activity都必須要在AndroidManifest.xml配置文件中聲明,否則系統將不識別也不執行該Activity。

二、創建一個Activity

  1. 自定義類繼承系統Activity
  2. 複寫Activity中Onreate方法
  3. 在佈局文件夾中書寫相應的佈局文件
  4. 調用setContent(R.layout.activity_main)
    //參數爲佈局文件中的相應的文件名
  5. 在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對象在當前的棧中只存在一個。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章