Android Intent(意圖)介紹

對於Android Intent大家肯定不陌生,Intent顧名思義就是“意圖”的意思。其實這個“意圖”有點不好理解。其實簡單點就是我想要“幹什麼”。你比如說,我想要“去火車站”、我想要“啓動一個Activity”、我想要“啓動一個server”、我想要XXX都是意圖。Intent有顯式Intent和隱式Intent兩種情況。


那麼問題來了:

一.那到底什麼樣的Intent是顯式的Intent,什麼樣的Intent是隱式的Intent呢?

爲了回答這個問題,請看下面對於隱式Intent和顯式Intent的具體介紹


1 隱式Intent

說起隱式Intent就不得不先說在清單文件(AndroidManifest.xml)中的intent-filter。你隨便創建一個Android 項目都會在清單文件中看見intent-filter,顧名思義就是Intent的過濾器。而且一個Activity組件的聲明中,可以有多個intent-filter。當然也可以沒有intent-filter。


舉個例子如下:

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

    <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/AppTheme">
        <!--1個intent-filter-->
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <!--沒有intent-filter-->
        <activity android:name=".Main2Activity" />

        <!--多個intent-filter-->
        <activity android:name=".Main3Activity">
            <intent-filter>
                <action android:name="com.mytest.MyIntentAction" />

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

                <data android:mimeType="aa/bb"/>
            </intent-filter>
            <intent-filter>
                <action android:name="com.mytest.MyIntentAction1" />

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

                <data android:scheme="myIntent1" android:host="8080"/>
            </intent-filter>
            <intent-filter>
                <action android:name="com.mytest.MyIntentAction2" />

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

                <data android:scheme="myIntent2"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

intent-filter實行“白名單”管理,即只列出組件樂意接受的Intent,但intent-filter只會過濾隱式Intent,顯式的Intent會直接傳送到目標組件。 Android組件可以有一個或多個intent-filter,每個intent-filter之間相互獨立,只需要其中一個intent-filter中的所有過濾條件條件(Action、Data、Category)全部被滿足則驗證通過。就說明該Intent是可以啓動該Activity的。除了用於過濾廣播的intent-filter可以在代碼中創建外,其他的intent-filter必須在AndroidManifest.xml文件中進行聲明。

intent-filter中具有和Intent對應的用於過濾Action,Data和Category的字段,一個隱式Intent要想被一個組件處理,必須匹配這三個(Action,Data和Category字段。下面具體介紹一下這三個字段

1.1 Action
檢查 Action 儘管一個Intent只可以設置一個Action,但一個Intentfilter可以持有一個或多個Action用於過濾,到達的Intent只需要匹配其中一個Action即可。 深入思考:如果一個Intentfilter沒有設置Action的值,那麼,任何一個Intent都不會被通過;反之,如果一個Intent對象沒有設置Action值,那麼它能通過所有的Intent-filter的Action檢查。

1.2 Data
檢查 Data 同Action一樣,Intent-filter中的Data部分也可以是一個或者多個,而且可以沒有。每個Data包含的內容爲URL和數據類型,進行Data檢查時主要也是對這兩點進行比較,比較規則: 如果一個Intent對象沒有設置Data,只有Intent-filter中也沒有設置Data時纔可通過檢查。 如果一個Intent對象包含URI,但不包含數據類型:僅當Intent-filter也不指定數據類型,同時它們的URI匹配,才能通過檢測。 如果一個Intent對象包含數據類型,但不包含URI:僅當Intentfilter也沒指定URL,而只包含數據類型且與Intent相同,才通過檢測。 如果一個Intent對象既包含URI,也包含數據類型(或數據類型能夠從URI推斷出),只有當其數據類型匹配Intent-filter中的數據類型,並且通過了URL檢查時,該Intent對象才能通過檢查。
其中URL由四部分組成:它有四個屬性scheme、host、port、path對應於URI的每個部分。
例如:content://com.wjr.example1:121/files
       scheme部分:content
       host部分:com.wjr.example1
       port部分:121
       path部分:files

host和port部分一起構成URI的憑據(authority),如果host沒有指定,那port也會被忽略。
這四個屬性是可選的,但他們之間並不是完全獨立的。要讓authority有意義,scheme必須要指定。要讓path有意思,scheme和authority必須指定。Intent-filter中的path可以使用通配符來匹配path字段,Intent和Intent-filter都可以用通配符來指定MIME類型。

1.3Category
檢查 CategoryIntent-filter中可以設置多個Category,Intent中也可以含有多個Category,只有Intent中的所有Category都能匹配到Intentfilter中的Category,Intent才能通過檢查。也就是說,如果Intent中的Category集合是Intent-filter中Category的集合的子集時,Intent才能通過檢查。如果Intent中沒有設置Category,則它能通過所有Intent-filter的Category檢查。 如果一個Intent能夠通過不止一個組件的Intent-filter,用戶可能會被問哪個組件被激活。如果沒有目標找到,會產生一個異常。

Intent-filter
應用程序的組件爲了告訴Android自己能響應、處理哪些隱式Intent請求,可以聲明一個甚至多個IntentFilter。每個 IntentFilter描述該組件所能響應Intent請求的能力——組件希望接收什麼類型的請求行爲,什麼類型的請求數據。比如之前請求網頁瀏覽器這 個例子中,網頁瀏覽器程序的IntentFilter就應該聲明它所希望接收的Intent Action是WEB_SEARCH_ACTION,以及與之相關的請求數據是網頁地址URI格式。
如何爲組件聲明自己的IntentFilter? 常見的方法是在AndroidManifest.xml文件中用屬性描述組件的IntentFilter。
前面我們提到,隱式Intent和IntentFilter進行比較時的三要素是Intent的Action、Data以及Category。實際上,一個隱式Intent請求要能夠傳遞給目標組件,必要通過這三個方面的檢查。如果任何一方面不匹配,Android都不會將該隱式Intent傳遞給目標組件。


講完了AndroidManifest.xml中的Intent-filter.就要看一下如何在代碼中一個隱式的Intent,去啓動一個組件。下面我們來看一個代碼例子,我創建了一個Android 項目,除了默認的MainActivity我又增加了兩個Activity:Main2Activity、Main3Activity。


其中Main2Activity由MainActivity啓動,暫時不看啓動Main2Activity的代碼,現在我們先看Main2Activity中使用隱式的Intent啓動Main3Activity的代碼。根據AndroidManifest.xml中Main3Activity的聲明來看,有三個intent-filter可以啓動Main3Activity,所以我隨機選一個intent-filter進行Intent的設置就可以了。我選用第三個intent-filter來啓Main3Activity。

            <intent-filter>
                <action android:name="com.mytest.MyIntentAction2" />

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

                <data android:scheme="myIntent2"/>
            </intent-filter>

AndroidManifest.xml中的action中的內容和Data中的內容都是我隨便寫的,因爲在android默認的那些action和data的數據中也是一個字符串,所以我們可以設置其爲任意字符串。根據這個intent-filter我在Main2Activity.java中的代碼實現如下:

package com.mytest;

import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class Main2Activity extends AppCompatActivity {

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

        //創建隱式Intent
        Intent intent = new Intent();

        //爲隱式Intent添加過濾Action,Data和Category的字段,
        // 不是說必須這三個字段同時有,這個設置那些是根據清單文件中Main3Activity的某一個intent-filter確定的
        intent.setAction("com.mytest.MyIntentAction2");
        intent.addCategory("android.intent.category.DEFAULT");
        intent.setData(Uri.parse("myIntent2:" + 110));//後邊的110是隨便加的,暫時沒有什麼具體的意思,這就是他的一個用法

        //啓動Main3Activity
        startActivity(intent);
    }
}

這就是使用隱式的Intent啓動組件。


2 顯式Intent

其實顯式Intent就很簡單了,我們直接來看代碼。我在MainActivity.java中使用顯式Intent啓動Main2Activity,代碼如下

package com.mytest;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

        //創建顯示Intent
        Intent intent = new Intent(getApplicationContext(),com.mytest.Main2Activity.class);

        //啓動Activity
        startActivity(intent);
    }
}

這就是顯式的Intent去啓動組件。


總的一句話,如果創建Intent的時候,明確指出了要啓動的class的名字,就是顯示Intent。如果沒有明確的指出要啓動的class的名,而是通過設置intent的過濾字段啓動class,就是隱式Intent.


二.什麼時候用顯示Intent,什麼時候用隱式Itent呢?

一句話:當你啓動自己寫的同一個APP中的Activity時使用顯示Intent,當你要啓動其他人寫APP中的Activity時使用隱式Intent。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章