Android四大組件之Activity

1、什么是Activity?

Activity是安卓四大組件之一,主要用來與用戶進行交互。除了一些用來后臺啟動一些服務的程序,基本上每個程序都會包含Activity的,想一些簡單的程序,比如在學習安卓的時候,可能就只有簡單的一個Activity,但是,在實際的開發(fā)中,一個程序至少也會由幾十個Activity組成。

2、加載布局

在Activity中加載布局的方法也很簡單,只要在onCreate()方法中調(diào)用setContentView()方法,然后將要調(diào)用的布局文件傳進setContentView()方法即可,當然,也可以用java代碼進行布局的構(gòu)建,但是并不推薦這樣子,因為這樣代碼量過大,而且也不方便,在這里更加推薦使用xml文件進行布局的構(gòu)建。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);//加載布局文件
    }

3、在AndroidManifest.xml中注冊創(chuàng)建的Activity

每創(chuàng)建一個Activity,都需要在AndroidManifest.xml中注冊,沒有經(jīng)過注冊的Activity,不僅沒法運行,更會導致程序奔潰閃退。雖然我們在使用Android Studio創(chuàng)建Acitivity的時候,會自動為我們注冊,但是我們也是要知道這件事的。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.helloworld">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.HelloWorld">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Activity的注冊,需要放在<application>標簽之內(nèi),然后通過<activity>標簽來對Activity進行注冊。
細心的人可以發(fā)現(xiàn),在注冊信息中,存在著以下語句:

<intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter>

這兩句語句通過<intent-filter>這個標簽來申明,具體信息代表著這個Activity注冊成為程序的主活動,也就是說,程序啟動的時候,最先啟動此Activity。
此外,在注冊信息中,另外的幾個屬性代表的含義如下:
android:allowBackup這個屬性代表改程序是否允許自動進行備份;
android:icon 這個屬性代表該程序要以哪個圖片作為程序的圖標;
android:label 這個代表程序的要顯示的名字;
android:roundIcon 表示程序指定了哪張圖片作為應用程序的圓形桌面圖標;android:supportsRtl 表示該程序是否支持從右往左顯示。
android:theme表示該程序要調(diào)用那種主題風格

4、Activity的跳轉(zhuǎn)
在學習Activity的跳轉(zhuǎn)之前,我們得先認識Intent,那么Intent是什么呢?
Intent:作為安卓程序中各組件進行交互的重要方式,可以用于啟動Activity,廣播,以及服務。不僅可以指明當前組件想要執(zhí)行的動作,而且可以攜帶數(shù)據(jù)進行交互。Intent一般可以分為顯示Intent和隱式Intent。
(1)顯示Intent

mTurnSecondButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });

在上面的例子中,當我們點擊mTurnSecondButton這個按鈕的時候,程序會跳轉(zhuǎn)到SecondActivity這個活動中,當中我們使用了Intent(Context packageContext, Class<?> cls)這個構(gòu)造函數(shù)來創(chuàng)建Intent實例,在這個構(gòu)造方法中,需要傳入兩個參數(shù),一個是上下文對象,另一個則是指定想要跳轉(zhuǎn)的Activity,最后,調(diào)用startActivity()這個方法,傳入Intent參數(shù)便可以通過顯示Intent的方式啟動另一個Activity了。
(2)隱式Inent
隱式Intent是通過添加action,category等信息,然后交由系統(tǒng)自行分析啟動哪個Activity的方法。如下所示,在注冊Activity的時候添加所需要的action以及category。

<activity
            android:name=".SecondActivity"
            android:exported="false" >
            <intent-filter>
                <action android:name="android.intent.test.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.MY_INTENT"/>
            </intent-filter>
        </activity>

然后在啟動的邏輯代碼中進行如下操作:

mTurnSecondButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("android.intent.test.ACTION_START");
                intent.addCategory("android.intent.category.MY_INTENT");
                startActivity(intent);
            }
        });

當action信息和category信息都對應上的時候,系統(tǒng)便會去啟動對應的Activity。有一種特殊的情況,當我們在注冊Activity的時候,可以直接這么寫:

<activity
            android:name=".SecondActivity"
            android:exported="false" >
            <intent-filter>
                <action android:name="android.intent.test.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

android.intent.category.DEFAULT 這個是一個默認的category,在我們調(diào)用startActivity()這個方法的時候,會自動加載進去,因此,如果按照上面這樣寫得話,我們在使用隱式Intent的時候只需要這么寫:

Intent intent = new Intent("android.intent.test.ACTION_START");
startActivity(intent);

另外,在使用隱式Intent去啟動Activity的時候,有一個踩坑點,就是在上面使用隱式Intent的第一種方法,也就是使用我們自己定義的category的時候,一定要將android.intent.category.DEFAULT這個在注冊的時候也加進去,否則會出現(xiàn)找不到要啟動的Acitivity,從而導致程序運行奔潰。

5、攜帶數(shù)據(jù)到下一個Activity

在前面介紹過,Intent不僅可以指明控件的意圖,還可以攜帶數(shù)據(jù),在這里,我們變使用Intent的另一個功能:攜帶數(shù)據(jù)進行交互。
其實通過Intent攜帶數(shù)據(jù)進行交互也很簡單,只需要調(diào)用Intent當中的putExtra()方法就可以了,這個方法通過鍵值對的方式進行數(shù)據(jù)的攜帶保存。例如:

              String data = "I Love Android!";
              Intent intent = new Intent(MainActivity.this,SecondActivity.class);
              intent.putExtra("intent_string",data);
              startActivity(intent);

putExtra()方法需要傳入兩個參數(shù),一個是“鍵”,也就是上面代碼中的intent_string,另一個是“值”,也就是上面中的data這個字符串。最后通過 startActivity(intent)將數(shù)據(jù)傳送到下一個Activity當中。
既然有傳遞數(shù)據(jù),那么必然就有獲取數(shù)據(jù),否則,數(shù)據(jù)的傳遞就沒有意義了。通過Intent發(fā)送的數(shù)據(jù),獲取方法如下:
(1)通過getIntent()的方法獲取啟動當前Activity(SecondActivity)的Intent。
(2)通過getStringExtra()的方法獲取傳遞的數(shù)據(jù),例子中傳遞的為String類型數(shù)據(jù),因此這里就使用getStringExtra()的方法,根據(jù)傳遞數(shù)據(jù)類型的不同,也可以使用getBooleanExtra()或者getIntExtra()等等方法。

Intent intent = getIntent();
String data = intent.getStringExtra("intent_string");
tv_getIntent.setText(data);

例子中,我們通過一個TextView來顯示獲取的數(shù)據(jù),效果如下:


Intent.png

6、返回數(shù)據(jù)到上一個Activity
(1)使用startActivityForResult()來啟動下一個Activity

mTurnSecondButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              Intent intent = new Intent(MainActivity.this,SecondActivity.class);
              startActivityForResult(intent,1);
            }
        });

在這里我們使用startActivityForResult()來啟動下一個Activity,傳入了唯一的Request Code,值為1。這個數(shù)值后面在獲取返回的數(shù)值的時候,還要作為判斷的依據(jù)。
(2)使用setResult()方法返回數(shù)據(jù)

btn_forRusult.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent1 = new Intent();
                intent1.putExtra("data_return","Turn to the FirstActivity!!");
                setResult(RESULT_OK,intent1);
                finish();
            }
        });

在上面的例子中,先構(gòu)建了一個Intent來傳遞數(shù)據(jù),然后調(diào)用setResult()的方法,改方法接收兩個參數(shù),第一個參數(shù)用于向上一個Activity返回處理的結(jié)果,一般傳遞RESULT_OK或者RESULT_CANCELED這兩個參數(shù);第二個參數(shù)則是帶著數(shù)據(jù)的Intent。
(3)在返回上一個Activity后調(diào)用onActivityResult()方法。

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        switch (requestCode){
            case 1:
                if (resultCode == RESULT_OK){
                    String dataReturn = data.getStringExtra("data_return");
                    Log.d("Activity",dataReturn);
                }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

onActivityResult()方法需要傳入3個參數(shù),第一個是requestCode,是我們啟動下一個Activity是傳入的請求碼,也就是上面例子中的1;第二個是resultCode,是我們在返回數(shù)據(jù)時傳入的處理結(jié)果,也就是上面例子中的RESULT_OK;最后一個是攜帶著是數(shù)據(jù)的Intent。
上面的例子先去判斷requestCode,因為一個Activity中,可能會存在不止一處用startActivityForResult()來啟動下一個Activity,因此,通過唯一的requestCode來判斷是哪個Activity返回的數(shù)據(jù),再通過resultCode來判斷處理結(jié)果,最后取出返回的數(shù)據(jù)并打印出來。

7、Activity的啟動模式
Activity的啟動模式有4種,分別為standard、singleTop、singleTask和singleInstance。Activity的啟動模式可以在AndroidManifest.xml中給<activity>標簽指定android:launchMode屬性來選擇需要的啟動模式。
(1)standard模式
standard模式是默認的啟動模式,如果沒有對Activity進行特殊的聲明的話,都是屬于standard模式。在standard模式下,系統(tǒng)每次都會創(chuàng)建該活動的一個新的實例。
首先我們在AndroidManifest.xml中將對象Activity設置成standard的啟動模式。

<activity
            android:name=".setupFirstActivity"
            android:launchMode="standard"
            android:exported="false" />

接著將按鈕的事件設置為啟動本Activity。然后點擊3次按鈕,打開信息過濾。


image.png

從上圖中可以看出,F(xiàn)irstSetupActivity創(chuàng)建了3次。然后我們一直按返回鍵,知道退出桌面。


image.png

我們會發(fā)現(xiàn),我們需要按4次返回鍵,才能退出到桌面,這是因為standard模式,會不管返回棧里面是什么情況,都會新創(chuàng)建一個Activity實例,我們啟動了3次setupFitstActivity,再加上本身存在一個,我們就需要返回4次,才能將返回棧中的Activity全部退出,然后到達桌面。
(2)singleTop模式

從上面的例子中,或許我們可以看到standard模式確實存在一些不太合理的地方,我們不妨來看一下第二種啟動模式--singleTop模式,在這種模式下,如果要啟動的Activity已經(jīng)是返回棧的棧頂了,那么這時候就不會再去創(chuàng)建一個Activity實例了,相當于是直接復用了棧頂?shù)腁ctivity。
復用上面例子中的程序,將啟動模式改成singleTop模式,同樣是點擊3次按鈕。我們會發(fā)現(xiàn)從程序運行到點擊完3次按鈕,Activity就只創(chuàng)建了一次。


image.png

(3)singleTask模式
在singleTop模式下,雖然在棧頂?shù)腁ctivity不會被重新創(chuàng)建,但是如果要啟動的Activity是存在于返回棧的,只是不是再棧頂,那么它還是會被重新創(chuàng)建的。為了讓整個上下文當中一個Activity不被重復創(chuàng)建,只有一個實例,我們可以使用第三種啟動模式--singleTask模式。在這個模式之下,系統(tǒng)每次啟動該Activity的時候,都會檢查返回棧中是否存在該Activity的實例,如果存在,則不再創(chuàng)建,把這個Activity實例上面的所有Activity全部彈出棧,讓這個Activity成為棧頂。
我們將setupFirstActivity的啟動模式改成singleTask模式,然后將Button的事件改成跳轉(zhuǎn)到setupSecondActivity,然后將setupSecondActivity的按鈕點擊事件設置成跳轉(zhuǎn)到setupFirstActivity,完成代碼編寫之后,完成如下操作:在setupFirstActivity啟動setupSecondActivity,然后再從setupScondActivity啟動setupFirstActivity,我們可以從過濾信息中看到如下信息:
image.png

可以看到這時候我們啟動setupFirstActivity的時候,并沒有執(zhí)行onCreate()的方法,而是直接執(zhí)行了onRestart(),并且可以看到,setupSecondActivity直接執(zhí)行了onDestroy()的方法進行了銷毀。
(4)singleInstance模式
不同于以上3中啟動模式,singleInstance模式是直接開辟一個新的返回棧出來的。
創(chuàng)建一個新的setupThirdActivity,然后將setupSecondActivity的啟動模式改成singleInstance模式,然后在每個Activity的onCreate()方法里面打印當前Activity的返回棧id,通過過濾信息,可以看到如下信息:


image.png

從圖片中可以看到,setupFirstActivity和setupThirdActivity的返回棧的id是一樣的,都是26,但是setupSecondActivity的返回棧的id是27,這是由于我們將setupSecondActivity的啟動模式改成singleInstance了,在啟動這個Activity的時候,重新創(chuàng)建了一個返回棧,并且,這個返回棧只有這一個Activity。
接著我們按返回鍵,我們會發(fā)現(xiàn),從setupThirdActivity會調(diào)到setupFirstActivity,然后再按一次返回鍵,才會到setupSecondActivity。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容