Android Activity 中 Intent 的使用總結(jié)

1、何為 Intent

Intent(意圖)主要用于 Android 各組件之間的交互,它可以指明當(dāng)前組件想要執(zhí)行的動作,也可以傳遞數(shù)據(jù)。一般來說,Intent 常被用來啟動 Activity、Service 以及 BroadCastReceiver。
Intent 分為顯式 Intent 和隱式 Intent,先來了解一下顯示 Intent。

2、顯式 Intent

在 Intent 的參數(shù)中明確的設(shè)置要跳轉(zhuǎn)的組件的包名和類名并跳轉(zhuǎn),叫顯式 Intent。
具體使用方法如下:

mBtnIntent.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View pView) {
           Intent lIntent = new Intent(MainActivity.this, SecondActivity.class);
           startActivity(lIntent);
     }
});

效果:

顯示 Intent 跳轉(zhuǎn).gif

3、隱式 Intent

相比顯示 Intent 明確指明想要啟動的組件包名,隱式 Intent 恰好相反,它不明確指明想要啟動哪一個組件,而是在清單文件下相應(yīng)組件標(biāo)簽下配置 <intent - filter> 內(nèi)容,通過設(shè)置 Action、Data、Category,讓系統(tǒng)來自動篩選本次意圖想要啟動的組件。
那我們現(xiàn)在就去修改一下示例中的 SecondActivity 的 <intent - filter> 吧:

<activity android:name=".SecondActivity">
     <intent-filter>
           <action android:name="com.ginkwang.activitysample.ACTION_START"/>
           <category android:name="android.intent.category.DEFAULT"/>
     </intent-filter>
</activity>

我們配置了 action 和 category 兩個標(biāo)簽,來了解一下這兩個標(biāo)簽的含義:

  • action
    這個標(biāo)簽是必須添加的,其內(nèi)容有系統(tǒng)內(nèi)置的(詳見 Android Intent Action 大全),也可以自定義。

  • category
    表示組件的類別,一個組件可以配置多個 category 標(biāo)簽。常用的 category 標(biāo)簽有3個:

    • DEFAULT —— 默認(rèn)動作

    • HOME —— 設(shè)置為本地桌面應(yīng)用

    • LAUNCHER —— 項(xiàng)目主 Activity

      其中 DEFAULT 是最常用的標(biāo)簽,本例中也是使用的 DEFAULT。

然后再修改一下代碼中啟動組件的邏輯,改為隱式 Intent 啟動:

mBtnIntent.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View pView) {
           Intent lIntent = new Intent("com.ginkwang.activitysample.ACTION_START");
           startActivity(lIntent);
     }
});

這里有個問題,隱式 Intent 不是要 action 和 category 兩個標(biāo)簽都要一一對應(yīng)才能啟動組件的嗎?
對,是這樣的沒錯。但是咱們在 category 標(biāo)簽下設(shè)置的是默認(rèn)動作 —— DEFAULT,它會在 startActivity() 方法執(zhí)行時,自動將 category 添加到 Intent 中。
同樣,如果 category 設(shè)置的是別的自定義的類別的話,就需要我們自己在啟動組件時填寫 category 信息了。
現(xiàn)在我們重新啟動一下應(yīng)用:

隱式Intent 跳轉(zhuǎn).gif

<intent - filter> 的兩個標(biāo)簽都介紹完了,接下來我們來看一下 data 標(biāo)簽。
data 代表數(shù)據(jù)檢測,用于精確的指定當(dāng)前活動能夠相應(yīng)什么類型的數(shù)據(jù)。data 標(biāo)簽可配置如下內(nèi)容:

  • android:host:指定主機(jī)名,例如:google.com

  • android:port:制定主機(jī)端口,例如: 80

  • android:path:指定URL的有效路徑值,例如: /index/examples

  • android:mimeType:指定組件可以執(zhí)行的數(shù)據(jù)類型,例如:image/jpeg,video/*

  • android:scheme:指定特定的模式,例如:content,http

和 action、category 一樣,只有 data 標(biāo)簽中指定的內(nèi)容與 Intent 中攜帶的 data 內(nèi)容相同時,當(dāng)前活動才能響應(yīng) Intent。
接下來展示,調(diào)用系統(tǒng)瀏覽器并打開指定網(wǎng)址:

mBtnBrowser.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View pView) {
         Intent intent = new Intent();
         intent.setAction("android.intent.action.VIEW");
         Uri url = Uri.parse("https://www.baidu.com/");
         intent.setData(url);
         startActivity(intent);
     }
});

我們先定義了一個系統(tǒng)內(nèi)置的 action 常量,然后通過 Uri.parse 方法將百度網(wǎng)址解析成一個 Uri 對象,最后通過 Intent 的 setData 方法將 Uri 對象傳遞進(jìn)去。
看一下效果:

隱式Intent 調(diào)用本地瀏覽器.gif

調(diào)用本地瀏覽器的操作并不難,其實(shí)我們也可以新建一個活動,并讓它響應(yīng)打開網(wǎng)頁的操作(此處的場景可以想象一下在某 APP 中點(diǎn)擊一段網(wǎng)址,系統(tǒng)會自動篩選可以打開網(wǎng)頁的 APP,然后給你一個選擇,用哪個 APP 打開這段網(wǎng)址)。
上代碼:
新建一個 ThirdActivity,代碼不表。然后在清單文件中配置 <intent-filter> ,

<activity android:name=".ThirdActivity">
     <intent-filter>
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:scheme="https"/>
     </intent-filter>
</activity>

注意,最重要的一句就是 <data android:scheme="https"/>
,這表明此活動接收的數(shù)據(jù)協(xié)議為 https(應(yīng)為我們測試的百度網(wǎng)址是 https 協(xié)議的),這樣就表明 ThirdActivity 可以和瀏覽器一樣,可以打開網(wǎng)頁了。
注意:
這個操作我只在原生 Android 系統(tǒng)上面測試成功了,在 MIUI 和 FLYME 上面則沒有選擇打開操作的過程,直接就在系統(tǒng)瀏覽器上面打開網(wǎng)址了。

4、Intent 傳遞數(shù)據(jù)

使用 Intent 可以打開活動,那能不能打開活動的同時,給下一個活動傳遞數(shù)據(jù)呢?答案當(dāng)然是可以的。使用 Intent 的 putExtra 方法即可,看代碼;

Intent lIntent = new Intent(MainActivity.this, SecondActivity.class);
lIntent.putExtra("intent_data", "hello_second_activity");
startActivity(lIntent);

通過 Intent 打開 SecondActivity,然后通過 putExtra 方法給 SecondActivity 傳遞數(shù)據(jù)。putExtra 接收兩個參數(shù),第一個參數(shù)是本次傳值的 key,第二個參數(shù)才是傳的值 value。
然后 SecondActivity 接收傳遞值的代碼:

//接收 MAinActivity 傳遞來的數(shù)據(jù)
String intentStr = getIntent().getStringExtra("intent_data");
Toast.makeText(SecondActivity.this, intentStr, Toast.LENGTH_LONG).show();

這里的邏輯也十分簡單,通過 getIntent 獲取到 Intent,然后再調(diào)用 getStringExtra 方法,傳入 MainActivity 里約定好的 key 值,就接收到 Intent 傳遞來的數(shù)據(jù)了。
剛才演示的 Intent 傳遞的是 String 型的數(shù)據(jù),同理 Integer、Boolean 等基本數(shù)據(jù)類型數(shù)據(jù),都可以按照上面的操作進(jìn)行傳遞,只是在接收的時候按照相應(yīng)的數(shù)據(jù)類型調(diào)用相應(yīng)的方法進(jìn)行接收就 OK 了。
那如果有一個實(shí)體類對象要進(jìn)行傳遞呢?
總不能將其字段一一拆分出來然后按照基本數(shù)據(jù)類型的傳遞方法進(jìn)行傳遞吧?這樣不是不行,只是太繁瑣了。如果這個類里面有50個字段的話,那工程量是有多大?
好了,不啰嗦。Intent 有一個方法 putExtras 可以實(shí)現(xiàn)我們的需求。直接上代碼:
先新建一個實(shí)體類,取名 IntentTestBean
,并實(shí)現(xiàn) Serializable 類,將其序列化:

public class IntentTestBean implements Serializable {
?
   private String name;
   private String age;
   private String sex;
?
   public String getName() {
       return name;
   }
?
   public void setName(String pName) {
       name = pName;
   }
?
   public String getAge() {
       return age;
   }
?
   public void setAge(String pAge) {
       age = pAge;
   }
?
   public String getSex() {
       return sex;
   }
?
   public void setSex(String pSex) {
       sex = pSex;
   }
?
   @Override
   public String toString() {
       return "IntentTestBean{" +
               "name='" + name + '\'' +
               ", age='" + age + '\'' +
               ", sex='" + sex + '\'' +
               '}';
   }
}

我們從 SecondActivity 中往 ThirdActivity 傳遞實(shí)體類,那 SecondActivity 里面的邏輯為:

/**
     * 向 ThirdActivity 發(fā)送實(shí)體類數(shù)據(jù)
     */
   private void intentBean() {
       IntentTestBean lIntentTestBean = new IntentTestBean();
       lIntentTestBean.setName("ginkwang");
       lIntentTestBean.setAge("24");
       lIntentTestBean.setSex("男");
       Intent lIntent = new Intent(SecondActivity.this, ThirdActivity.class);
       Bundle lBundle = new Bundle();
       lBundle.putSerializable("intent_bean", lIntentTestBean);
       lIntent.putExtras(lBundle);
       startActivity(lIntent);
   }

先把 IntentTestBean 類賦值,然后新建 Intent,指定跳轉(zhuǎn)目標(biāo),因?yàn)槲覀円獋鬟f的是對象,所以必須要使用 BundleBundle主要用于傳遞數(shù)據(jù),它保存的數(shù)據(jù),是以key-value(鍵值對)的形式存在的
。新建 Bundle 對象 ,接著將 IntentTestBean 類傳入進(jìn) Bundle,然后調(diào)用 Intent 的 putExtras 方法,將實(shí)體類傳遞出去。
在 ThirdActivity 中接收數(shù)據(jù)的邏輯如下:

 //接收 SecondActivity 傳遞的實(shí)體類數(shù)據(jù)
       IntentTestBean lIntentTestBean = (IntentTestBean) getIntent().
               getSerializableExtra("intent_bean");
       if (lIntentTestBean != null) {
           Toast.makeText(ThirdActivity.this, lIntentTestBean.toString(), Toast.LENGTH_LONG).show();
       }

這里的邏輯很簡單,和接收 String 類型數(shù)據(jù)的方法類似,就是這里需要使用 getSerializableExtra 方法獲取實(shí)體類對象,另外還有一個類型強(qiáng)制轉(zhuǎn)換。
最終效果:

Intent 傳遞數(shù)據(jù).gif

5、Intent 傳遞數(shù)據(jù)

說完了傳遞數(shù)據(jù),接下來講一下 Intent 返回?cái)?shù)據(jù)給上一個活動。
利用 Intent 返回?cái)?shù)據(jù),就不能用 StartActivity 啟動活動了。Activity 中提供了一個 startActivityForResult 方法,此方法也可用于啟動活動,并在活動銷毀時傳遞數(shù)據(jù)給上一個活動。這正是我們想要的!
startActivityForResult 方法接收兩個參數(shù),第一個還是攜帶數(shù)據(jù)的 Intent,第二個是請求碼,用于回調(diào)時對數(shù)據(jù)來源的判斷。
看一下啟動活動的代碼:

Intent lIntent = new Intent(MainActivity.this, SecondActivity.class);
lIntent.putExtra("intent_data", "hello_second_activity");
startActivityForResult(lIntent, 1);

和之前幾乎一樣,就是把 startActivity 換成了 startActivityForResult,請求碼設(shè)置為1。
然后看一下 SecondActivity 中返回?cái)?shù)據(jù)的代碼:

//向 MainActivity 返回?cái)?shù)據(jù)
Intent lIntent = new Intent();
lIntent.putExtra("return_data", "hello_main_activity");
setResult(RESULT_OK, lIntent);
finish();

還是新建一個 Intent 對象,但不給它指定任何意圖,僅僅用作傳遞數(shù)據(jù)。接著調(diào)用 setResult 方法,此方法專門用于向上一個活動傳遞數(shù)據(jù),接收兩個參數(shù),第一個是 Intent,第二個是處理結(jié)果,一般使用 RESULT_OK 或 RESULT_CANCELED。最后調(diào)用 finish 方法銷毀當(dāng)前活動。
之后還要在 MainActivity 中重寫一個 onActivityResult 用作回調(diào):

@Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       switch (requestCode) {
           case 1://判斷請求碼是否為1,缺失是否從 SecondActivity 返回的
               if (resultCode == RESULT_OK) {//再判斷結(jié)果值看是否返回結(jié)果成功
                   String resultData = data.getStringExtra("return_data");
                   Toast.makeText(MainActivity.this, resultData, Toast.LENGTH_LONG).show();
               }
               break;
       }
   }

相關(guān)邏輯在代碼中都標(biāo)注好了,另外實(shí)體類的數(shù)據(jù)返回也是如此,這里就不貼代碼了。
最后,效果圖:

Intent 返回?cái)?shù)據(jù).gif

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

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

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