intent – 活動間傳遞資料

使用 Intent 在活動之間切換

從主活動跳轉到其他活動

使用顯式 Intent。

我們新增一個空白活動,命名為 AddCourseActivity,記得勾選「產生布局檔」。
但不要勾選 Launcher Activity 選項。

Intent

Intent 是 Android 程式中各元件之間互動的一種重要方式。
它不僅可以指明目前元件想要執行的動作,還能在不同元件之間傳遞資料。


Intent 分為:顯式 Intent 和隱式 Intent

Intent 有多個建構函式。
我在主活動的按鈕上實例化一個 Intent,從主活動跳到第二個活動。

// 先初始化一個 Intent,指定從哪裡到哪裡
Intent it = new Intent(FirstActivity.this, AddCourseActivity.class);
startActivity(it);Code language: JavaScript (javascript)

隱式 Intent 的使用

相較於顯式 Intent,隱式 Intent 不需要指明要啟動哪個活動,而是指定一系列更抽象的 action 和 category。

然後讓系統分析這個 Intent,幫我們找出合法的活動來啟動。

我們修改 AndroidManifest.xml。

給第二個活動加上 action 和 category。

action 用來指明這個活動可以回應此 action。

<activity android:name=".AddCourseActivity">
    <intent-filter>
        <action android:name="com.foxdevelop.www.activitydemo.ACTION_START" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>Code language: HTML, XML (xml)

只有當 Intent 能夠匹配活動的 action 和 category 時,該活動才能回應 Intent。

// 初始化一個 Intent,讓它去匹配 AndroidManifest.xml 中對應的 action
Intent it = new Intent("com.foxdevelop.www.activitydemo.ACTION_START");
startActivity(it);Code language: JavaScript (javascript)

為什麼不需要匹配 category?

因為我們的這個活動使用的是 android.intent.category.DEFAULT。

這是一個預設值。

當我們呼叫 startActivity 時,會自動傳入 DEFAULT。

每個 Intent 只能指定一個 action,但可以指定多個 category。

目前是 DEFAULT,所以我們不用額外添加。

如果需要添加其他 category:

// 初始化 Intent 匹配 action,同時加入 category
Intent it = new Intent("com.foxdevelop.www.activitydemo.ACTION_START");
it.addCategory("com.foxdevelop.www.activitydemo.MY_CATEGORY");
it.addCategory("com.foxdevelop.www.activitydemo.MY_CATEGORY1111111");
startActivity(it);Code language: JavaScript (javascript)

點擊「新增課程」選單後,程式出錯了。

原因是我們給 intent 增加了一個 category,但第二個活動並沒有宣告這個 category。

所以我們需要把這個 category 加上去。

<activity android:name=".AddCourseActivity">
    <intent-filter>
        <action android:name="com.foxdevelop.www.activitydemo.ACTION_START" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="com.foxdevelop.www.activitydemo.MY_CATEGORY" />
    </intent-filter>
</activity>Code language: HTML, XML (xml)

注意:

如果 intent 有多個 category,並不是只要符合其中一個就可以,而是「所有」category 都必須匹配才行。

<activity android:name=".AddCourseActivity">
    <intent-filter>
        <action android:name="com.foxdevelop.www.activitydemo.ACTION_START" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="com.foxdevelop.www.activitydemo.MY_CATEGORY" />
    </intent-filter>
</activity>Code language: HTML, XML (xml)
case R.id.add:
    // 初始化 Intent 匹配 action,同時加入 category
    Intent it = new Intent("com.foxdevelop.www.activitydemo.ACTION_START");
    it.addCategory("com.foxdevelop.www.activitydemo.MY_CATEGORY2222222");
    //it.addCategory("android.intent.category.DEFAULT");
    startActivity(it);
    break;Code language: JavaScript (javascript)

使用隱式 Intent 開啟網頁

隱式 Intent 還有很多其他功能可以實現。

它不只能啟動同一個程式的活動,還能啟動其他程式的活動。

這讓多個應用程式之間的功能共享成為可能。

例如微信聊天時,朋友傳給你一個地址,你可以選擇用 QQ 瀏覽器開啟。

下面我們來試試看:

Intent it = new Intent(Intent.ACTION_VIEW); // 系統內建的 Action
it.setData(Uri.parse("http://www.foxdevelop.com")); // 開啟一個網址
startActivity(it);Code language: JavaScript (javascript)

http:// 不能省略,否則會報錯。

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.foxdevelop.www.activitydemo, PID: 8917
                  android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=www.foxdevelop.com }
                      at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1809)
                      at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523)
                      at android.app.Activity.startActivityForResult(Activity.java:4224)
                      at android.support.v4.app.BaseFragmentActivityApi16.startActivityForResult(BaseFragmentActivityApi16.java:54)
                      at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:68)Code language: PHP (php)

使用隱式 Intent 撥打電話

可以呼叫 tel 協定來打電話

上節課我們用 http 協定開啟網域。

例如下面嘗試撥打 10010。

Intent it = new Intent(Intent.ACTION_DIAL); // 系統內建的 Action
it.setData(Uri.parse("tel:10010")); // 撥打這支電話,需要使用者確認
startActivity(it);Code language: JavaScript (javascript)

活動之間傳遞資料

Intent 可以傳遞資料

intent 英[ɪnˈtent] 美[ɪnˈtɛnt] 意圖,目的;意思,含義。

使用它的 putExtra 方法可以傳遞資料。

然後在第二個活動中,透過呼叫 getStringExtra 方法可以取得傳過來的資料。

在第二個活動中可以呼叫 getIntent 方法取得 Intent。

當然,如果傳的是整數,可以使用 getIntExtra 方法取得。

首先在第一個活動裡面:

Intent it = new Intent(FirstActivity.this, AddCourseActivity.class);
it.putExtra("site", "www.foxdevelop.com");
it.putExtra("name", "FoxDevelop");
startActivity(it);Code language: JavaScript (javascript)

接著在第二個活動取得 Intent 物件,然後就能取得裡面的值。

在第二個活動的 onCreate 方法裡:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add_course_acticity);
    Intent it = getIntent();
    String site = it.getStringExtra("site");
    String name = it.getStringExtra("name");
    int version = it.getIntExtra("version", 1);
    Log.e(TAG, site);
}Code language: JavaScript (javascript)

返回資料給前一個活動

當我們退出目前活動時

活動中有一個 startActivityForResult 方法,可以在活動銷毀前返回一個結果給上一個活動。

該方法接收兩個參數:第一個是 Intent,第二個是請求碼,用於之後的回調中判斷資料的來源。

在活動銷毀之前,使用 setResult 方法可以向上一個活動返回結果。一般使用 RESULT_OK 或 RESULT_CANCELED,第二個參數則是把帶資料的 Intent 傳回去。

我們可以給 Intent 使用 putExtra 設定值。

由於我們在上個活動使用了 startActivityForResult 來啟動第二個活動,所以當第二個活動銷毀後,會觸發第一個活動的 onActivityResult 方法。在這裡我們可以取得 Intent 和結果編碼。

如果使用者不是點擊按鈕退回,而是使用 back 鍵退回,這時需要重寫第二個活動的 onBackPressed 方法才行。

1. 在第一個活動啟動 Intent 時

Intent it = new Intent(FirstActivity.this, AddCourseActivity.class);
it.putExtra("site", "www.foxdevelop.com");
it.putExtra("name", "FoxDevelop");
it.putExtra("version", 1);
startActivityForResult(it, 1);Code language: JavaScript (javascript)

2. 第一個活動中重寫

public class FirstActivity extends AppCompatActivity {
    private static final String TAG = "FirstActivity";
    // 重寫第一個活動的方法,當第二個活動退出就會執行這裡的程式碼
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            String h = data.getStringExtra("hot");
            Log.d(TAG, h);
        }
        super.onActivityResult(requestCode, resultCode, data);
    }Code language: JavaScript (javascript)

3. 在第二個活動中

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add_course_acticity);

    // 取得上一個活動的資料
    Intent it = getIntent();
    String site = it.getStringExtra("site");
    String name = it.getStringExtra("name");
    int version = it.getIntExtra("version", 1);
    Log.e(TAG, site);

    // 給按鈕加上退回事件,在事件裡給 Intent 賦值,設定結果編碼,同時結束活動
    Button b = findViewById(R.id.button);
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent it = getIntent();
            it.putExtra("hot", "熱門課程");
            setResult(RESULT_OK, it);
            finish();
        }
    });
}Code language: JavaScript (javascript)

當我們退回主活動時,就會觸發事件並輸出日誌。

05-12 06:17:46.741 12960-12960/com.foxdevelop.www.activitydemo D/FirstActivity: 熱門課程

如果想要退回鍵也能返回資料

需要重寫 onBackPressed。

我們在第二個活動中重寫:

// 這個方法是當我們按退回鍵時觸發
@Override
public void onBackPressed() {
    Intent it = getIntent();
    it.putExtra("hot", "最新課程");
    setResult(RESULT_OK, it);
    finish();
}Code language: JavaScript (javascript)
05-12 06:23:08.654 13209-13209/com.foxdevelop.www.activitydemo D/FirstActivity: 熱門課程
05-12 06:23:16.405 13209-13209/com.foxdevelop.www.activitydemo D/FirstActivity: 最新課程
05-12 06:23:35.612 13209-13209/com.foxdevelop.www.activitydemo D/FirstActivity: 最新課程

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *