Android基礎(四)——Activity的兩種啟動方式、Intent初探
一、啟動Activity
一個activity跳轉到另外一個activity中的最簡單的方式就是使用下面的Activity方法:
public void startActivity(Intent intent);
可能會有人認為startActivity(...)方法是一個類方法,啟動activity就是針對Activity子類呼叫該方法。實際並非如此,activity呼叫startActivity(...)方法時,呼叫請求實際發給了作業系統。
準確地說,該方法呼叫請求是傳送給作業系統的ActivityManager。ActivityManager負責建立Activity例項並呼叫其onCreate(...)
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的原因所在。
通過制定Context與Class物件,然後呼叫intent的構造方法來建立Intent
一個應用的activity如需啟動另一個應用中的activity,就可以通過隱式Intent來處理。
2、隱式Intent
在介紹隱式Intent之前,得先知曉Intent的兩個屬性:
Intent的Action、Category兩個屬性的值都是一個普通的字串,其中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中設定一個按鈕,點選按鈕後會跳到SecondActivity,UI佈局太過簡單這裡就不說了。
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屬性,程式可呼叫Intent的setAction(String str)方法來設定Action屬性值;但一個Intent物件可以包括多個Category屬性,程式可呼叫Intent的addCategory(String str)方法來為Intent新增Category屬性。當程式建立Intent時,該Intent預設啟動Category屬性值為android.intent.category.DEFAULT常量的元件。
因此,雖然上面程式中的粗體字程式碼並未指定目標Intent的Category屬性,但該Intent已有一個值為android.intent.category.DEFAULT的Category屬性值,因此被啟動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>