1. 程式人生 > >Android基礎(四)——Activity的兩種啟動方式、Intent初探

Android基礎(四)——Activity的兩種啟動方式、Intent初探

一、啟動Activity

一個activity跳轉到另外一個activity中的最簡單的方式就是使用下面的Activity方法:

public void startActivity(Intent intent);

可能會有人認為startActivity(...)方法是一個類方法,啟動activity就是針對Activity子類呼叫該方法。實際並非如此,activity呼叫startActivity(...)方法時,呼叫請求實際發給了作業系統。

準確地說,該方法呼叫請求是傳送給作業系統的ActivityManagerActivityManager負責建立Activity例項並呼叫其onCreate(...)

方法。那麼,ActivityManager是如何知道該啟動哪一個Activity呢?答案就在於傳入startActivity(...)方法的Intent引數。

1、顯式intent

如下模板程式碼:

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate called.");
        setContentView(R.layout.activity_main);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(),SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}

點選之後可以從MainActivity中跳轉至SecondActivity。其中getApplicationContext()方法是用於獲取當前上下文,在這裡也可以用MainActivity.this替換。在啟動activity以前,ActivityManager會檢查確認指定的Class是否已在配置檔案中宣告。如果已經宣告,則啟動activity,應用正常執行。反之,則丟擲ActivityNotFoundException異常。這就是我們必須在manifest配置檔案中宣告應用全部activity的原因所在。

通過制定ContextClass物件,然後呼叫intent的構造方法來建立Intent

,這建立的屬於顯式Intent。同一應用中,我們使用顯式Intent來啟動activity

一個應用的activity如需啟動另一個應用中的activity,就可以通過隱式Intent來處理。

2、隱式Intent

在介紹隱式Intent之前,得先知曉Intent的兩個屬性:

IntentActionCategory兩個屬性的值都是一個普通的字串,其中Action代表該Intent所要完成的一個抽象“動作”,而Category則用於為Action增加額外的附加類別資訊。通常Action屬性會與Category屬性結合使用。

Action要完成的只是一個抽象動作,這個動作具體由哪個元件(或許是Activity或許是BroadcastReceiver)來完成,Actioin這個字串本身並不管。比如Android提供的標準Action:Intent.ACTION_VIEW,它只表示一個抽象的檢視操作,但具體檢視什麼、啟動哪個Activity來檢視,Intent.ACTION_VIEW並不知道——這取決於Activity<intent-filter.../>配置,只要某個Activity<intent-filter.../>配置中包含了該ACTION_VIEW,該Activity就有可能被啟動。

下面有一個簡單示例,在MainActivity中設定一個按鈕,點選按鈕後會跳到SecondActivityUI佈局太過簡單這裡就不說了。

MainActivity的程式碼如下:

public class MainActivity extends Activity {
    private final static String TAG = "MainActivity";
    public final static String TEXT="com.intent.action.ONLYATEST";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();//建立Intent物件
                intent.setAction(MainActivity.TEXT);//為Intent設定Action屬性(屬性值就是一個普通字串)
                startActivity(intent);
            }
        });
    }
}

    在上述程式程式碼中,

      Intent intent = new Intent();//建立Intent物件
      intent.setAction(MainActivity.TEXT);//為Intent設定Action屬性(屬性值就是一個普通字串)
      startActivity(intent);

指定了根據Intent來自動Activity——至於啟動哪個Activity,這取決於Activity配置中<intent-filter.../>元素的配置。

<intent-filter.../>元素是AndroidManifest.xml檔案中<activity.../>元素的子元素,前面已經介紹過,<activity.../>元素用於為應用程式配置Activity,<activity.../><intent-filter.../>子元素則用於配置該Activity所能“響應”的Intent

<intent-filter.../>元素裡通常可包含如下子元素。

0~N<action.../>子元素。

0~N<category.../>子元素。

0~1<data.../>子元素。

<intent-filter.../>元素也可以是<service.../><receiver.../>兩個元素的子元素,用於表明它們可以響應的Intent

<action.../><category.../>子元素的配置非常簡單,它們都可指定android:name屬性,該屬性的值就是一個普通字串。

<activity.../>元素的<intent-filter.../>子元素裡包含多個<action.../>子元素(相當於指定了多個字串)時,就表明該Activity能響應Action屬性值為其中任意一個字串的Intent

由於上面的程式制定啟動Action屬性為TEXT常量(常量值為com.intent.action.ONLYATEST)的Activity,也就要求被啟動的Activity對應的配置元素的<intent-filter.../>元素裡至少包括一個如下的<action.../>子元素:

<action android:name="com.intent.action.ONLYATEST"/>

需要注意的是,一個Intent物件最多隻能包括一個Action屬性,程式可呼叫IntentsetAction(String str)方法來設定Action屬性值;但一個Intent物件可以包括多個Category屬性,程式可呼叫IntentaddCategory(String str)方法來為Intent新增Category屬性。當程式建立Intent時,該Intent預設啟動Category屬性值為android.intent.category.DEFAULT常量的元件。

因此,雖然上面程式中的粗體字程式碼並未指定目標IntentCategory屬性,但該Intent已有一個值為android.intent.category.DEFAULTCategory屬性值,因此被啟動Activity對應的配置元素的<intent-filter.../>元素裡至少還包括一個如下的<category.../>子元素:

<category android:name="android.intent.category.DEFAULT"/>

下面是完整的AndroidManifest.xml檔案程式碼:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.z.activitydemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity">
            <intent-filter>
                <!-- 指定該Activity能響應Action屬性值為指定字串的Intent -->
                <action android:name="com.intent.action.ONLYATEST"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
    </application>

</manifest>