深入理解Intent和IntentFiler(一)


http://blog.csdn.net/u012637501/article/details/41080891

為了比較深刻的理解並靈活使用Intent,我計划將這部分的學習分為兩步:一是深入理解Intent基本概念以及其類;二是,通過實例來闡述如何靈活使用Intent來啟動一個組件以及實現組件之間的傳遞數據。
一、什么是Intent,有什么作用?
    Android的應用程序包括四大組件:Activity、contentProvider、Service、BroadcastReceiver,為了方便不同組件之間的交流通信,應用程序就采用了一種統一的方式啟動組件及傳遞數據,即使用Intent。            
    Intent封裝了Android應用程序需要啟動某個組件的"意圖",Intent類的對象是組件間的通信載體,一個Intent對象就是一組信息,其包含接收Intent組件所關心的信息(如action 和 Data)和Android 系統關心的信息(如Category等)。也就是說,發送"意圖"的組件通過Intent對象所包含的內容,來啟動指定的(即Component屬性)或通過篩選(即Action&Category屬性)的某(些)組件,然后實施相應的動作(即Action屬性)並傳遞相應的數據(即Data屬性)以便完成相應的動作。

二、Intent是如何實現組件間相互調用?

1.Intent實現
     
    上圖請求一個Activity組件的簡單的實現流程圖,算是用的最多的Intent解析實例。
   首先,發出"意圖"的組件,通過調用Context.startActivity(intent)開始啟動組件:發出"意圖"的組件傳入已經構好的Intent對象(為一組信息,它決定了是否能夠成功的啟動另一個組件);
   然后,調用"動作"實際的執行着Instrumentation對象,它是整個應用激活的Activity管理者,集中負責應用內所有Activity的運行。它有一個隱藏的方法execStartActivity方法,就是負責根據Intent啟動Activity。該方法去掉一些細節,它做得最重要的事情,就是將此調用,通過RPC的方式,傳遞到ActivityManagerService。
   最后,ActivityManagerService會將這些關鍵信息遞交給另一個服務PackageManagerService,此服務掌握整個軟件包及其各組件的信息,它會將傳遞過來的Intent,與已知的所有Intent Filters進行匹配(如果帶有Component信息,就不用比了)。如果找到了,就把相關Component的信息通知回AcitivityManagerService,在這里,會完成啟動Activity這個很多細節的事情。  
2.Intent匹配
    到底發出"意圖"的組件是如何找到所需的組件呢?在這里,Intent Filters就開始起作用了,Intent Filters定義在AndroidMainFest.xml文件中,每一個Activity都會有一個<Intent Filters/>元素,它包含了<action/>、<data/>等子元素。當我們的intent對象沒有包含Component信息時,這種"意圖"被稱之為隱形"意圖"。也就是說,"意圖"沒有指明具體要啟動哪個組件以及完成什么樣的動作。這時我們就需要通過Intent Filters中的子元素進行信息匹配,從而確定當前包含Intent Filters屬性的Activity是不是我們要啟動的那個(些)組件。即發送"意圖"組件配置好intent對象,被啟動組件實現Intent Filters屬性,最后,發送組件會根據被啟動組件AndroidMainFest.xml中的<Intent Filters/>信息來確定它是不是目標組件。

三、Intent對象詳解

  Intent類的對象是組件間的通信載體,利用Intent對象我們可以很方便的實現不同組件之間的通信。一個Intent對象就是一組信息,這些信息都是通過其Component、Action、Category、Data、Extra和Flag這7種屬性體現的。Intent代表了Android應用的啟動"意圖",Android應用將會根據Intent來啟動指定組件,至於到底啟動哪個組件,則取決於Intent的屬性。 
1.Action屬性
    Action屬性為一個普通的字符串,它代表了該Intent對象要完成一個什么樣的"動作"。當我們為Intent對象指明了一個action時,被啟動的組件就會依照這個動作的指示表現出相應的行為,比如查看、撥打、編輯等,需要注意的是一個組件(如Activity)只能有一個action。我們可以方便自己的應用程序組件之間的通信,自定義action的(字符串)創建新的動作;也可以直接使用Intent類中的靜態成員變量,比如ACTION_VIEW,ACTION_PICK,它們是Android中為action屬性預定義的一批action變量。
在設置Intent對象Action屬性時,有兩種:
[java]  view plain  copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. (1)自定義字符串  
  2. public final String CUSTOME_ACTION="intent.action.CUSTOME_JIANG";//字符串可以任意  
  3. Intent intent=new Intent();  
  4. intent.setAction(ActionAttr.CUSTOME_ACTION); //注意:ActionAttr為我們創建的類,也可以使用this.CUSTOME_ACTION  
  5. (2)使用系統預定action常量  
  6. Intent intent=new Intent();  
  7. intent.setAction(Intent.ACTION_CALL);    //其中ACTION_CALL為Intent類的靜態成員變量,可以類直接調用  
  8.                                         //對應字符串"android.intent.action.CALL"  
2.Data屬性
   Action屬性為Intent對象描述了一個"動作",那么Data屬性就為Intent對象的Action屬性提供了操作的數據。這里需要注意的是,Data屬性只接受一個Uri對象,一個Uri對象通常通過如下形式的字符串來表示:
Uri字符串格式:scheme://host:port/path 舉例: content://com.android.contacts/contacts/1或tel://18819463209
在設置Intent對象Data屬性時可以這樣:
[java]  view plain  copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. Intent intent=new Intent();  
  2. String data="content://com.android.contacts/contacts/1";  
  3. Uri uri=Uri.parse(data);//將字符串轉換為Uri  
  4. intent.setData(uri);  
  5. 或者  
  6. Intent intent=new Intent();  
  7. intent.setData(Uri.parse("content://com.android.contacts/contacts/1"));  

 博主筆記1:action屬性和data屬性為Intent所傳遞信息的主要部分,action/data屬性舉例:
ACTION_VIEW content://contacts/people/1 -- 傳遞的信息: 顯示 號碼為1的人相關信息
ACTION_DIAL content://contacts/people/1 -- 傳遞的信息:給編號為1的人 打 電話
ACTION_VIEW tel:123 -- 傳遞的信息:將號碼123 顯示
ACTION_DIAL tel:123 --傳遞的信息:  撥打 號碼123
ACTION_EDIT content://contacts/people/1 -- 傳遞的信息: 編輯編號為1的聯系人
ACTION_VIEW content://contacts/people/ -- 傳遞的信息:列出顯示所有聯系人.如果希望在查看某個聯系人,需要定義一個新的intent並且屬性設置為{ ACTION_VIEW content://contacts/N } 傳遞到一個新的Activity。
總結:action屬性、data屬性是intent的主要屬性。

3.Catagory屬性
    通過Action,配合Data或Type屬性可以准確的表達出一個完整的意圖了。但為了使的"意圖"更加精確,我們也給意圖添加一些約束,這個約束由"意圖"的Catagory屬性實現。一個意圖只能指定一個action屬性,但是可以添加一個或多個Catagory屬性。Category屬性可以自定義字符串實現,但為了方便不同應用之間的通信還可以設置系統預定義的Category常量。調用方法addCategory 用來為Intent 添加一個Category,方法removeCategory 用來移除一個Category;getCategories方法返回已定義的Category。
在設置Intent對象Categoty屬性時可以這樣:
[java]  view plain  copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. (1)自定義字符串  
  2. public final String CUSTOME_CATEGORY="intent.action.CUSTOME_CATEGORY";//字符串可以任意  
  3. Intent intent=new Intent();  
  4. intent.addCategory(ActionAttr.CUSTOME_CATEGORY);   
  5. (2)使用系統預定action、category常量  
  6.     以下代碼實現當點擊某個按鈕時,通過Intent對象實現返回HOME桌面。  
  7. Intent intent=new Intent();  
  8. intent.setAction(Intent.ACTION_MAIN);  
  9. intent.addCategory(Intent.CATEGORY_HOME);//返回Home桌面   

博主筆記2:一般來說Action屬性和Category屬性都是同時使用的。在Android中,所有應用主Activity(就是單獨啟動時候,第一個運行的那個Activity...),都需要能夠接受一個Category為 CATEGORY_LAUNCHER,Action為ACTION_Main的意圖。對於發出"意圖"的組件,我們可以通過setAction()、addCategory()方法為"意圖"添加action屬性或者同時添加Action、Category屬性;對於接收"意圖"的組件,在AndroidManifest.xm文件中,我們可以這樣設置:
<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ActionCateAttr"
            android:label="第一個Activity界面" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />            //默認Action
                <category android:name="android.intent.category.LAUNCHER" />    //默認Category
            </intent-filter>
        </activity>
     
        <activity
            android:name=".SecondaryActivity"
            android:label="第二個Activity界面" >
            <intent-filter>
                <action android:name="intent.action.JIANG_ACTION" />
                <category android:name="intent.action.JIANG_CATEGORY" />
                <category android:name="android.intent.category.DEFAULT" />    //默認Category
            </intent-filter>
        </activity>
注釋:發出"意圖"的Activity將Category為 CATEGORY_LAUNCHER,Action為ACTION_Main,接收"意圖"的Activity須設置一個默認的Category屬性CATEGORY_DEFAULT,這里不能將其設置為CATEGORY_LAUNCHER否者會報錯。另外,如果我們使用了系統預定義的action常量,則需要在AndroidManifest.xm文件中添加相應的權限,這方面的內容我們將在第二部分講到。

4.Type屬性
   Type屬性用於指定該Data所指定Uri對應的MIME類型,這種類型可以是任何自定義的MIME類型,只要符合abc/xyz格式的字符串即可。這里需要注意的是,Type屬性和Data屬性一般會出現相互覆蓋的情況,如果希望Intent既有Data屬性也有Type屬性,必須通過setDataAndType()方法來實現。對於Type屬性的理解,我記得有篇博文是這樣作比方的:說了Data,就必須要提Type,很多時候,會有人誤解,覺着Data和Type的差別,就猶如泡妞和泡馬子之間的差別一樣,微乎其微。但其實不然,Type信息,是用MIME來表示的,比如text/plain,這樣的東西。說到這里,兩者差別就很清晰了,Data就是門牌號,指明了具體的位置,具體問題具體分析,而type,則是強調物以類聚,解決一批量的問題。實際的例子是這樣的,比如,從某個應用撥打一個電話,會發起的是action為ACTION_DIAL且data為tel:xxx這樣的Intent,對應的人類語言就是撥打xxx的電話,很具象。而如果使用type,就寬泛了許多,比如瀏覽器收到一個未知的MIME類型的數據(比如一個視頻...),就會放出這樣的Intent,求系統的其他應用來幫助,表達成自然語言應該就是:查看pdf類文檔,這樣的。

博主筆記3:MIME類型?
 

    MIME(Multipurpose Internet Mail Extensions)多用途互聯網郵件擴展類型就是設定某種擴展名的文件用一種應用程序來打開的方式類型,當該擴展名文件被訪問的時候,瀏覽器會自動使用指定應用程序來打開。多用於指定一些客戶端自定義的文件名,以及一些媒體文件打開方式。最早的HTTP協議中,並沒有附加的數據類型信息,所有傳送的數據都被客戶程序解釋為超文本標記語言HTML 文檔,而為了支持多媒體數據類型,HTTP協議中就使用了附加在文檔之前的MIME數據類型信息來標識數據類型。MIME意為多功能Internet郵件擴展,它設計的最初目的是為了在發送電子郵件時附加多媒體數據,讓郵件客戶程序能根據其類型進行處理。然而當它被HTTP協議支持之后,它的意義就更為顯著了。它使得HTTP傳輸的不僅是普通的文本,而變得豐富多彩。每個MIME類型由兩部分組成,前面是數據的大類別,例如聲音audio、圖象image等,后面定義具體的種類。

常見的MIME類型(通用型):
超文本標記語言文本 .html text/html
xml文檔 .xml text/xml
XHTML文檔 .xhtml application/xhtml+xml
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
PDF文檔 .pdf application/pdf
Microsoft Word文件 .word application/msword
PNG圖像 .png image/png
GIF圖形 .gif image/gif
JPEG圖形 .jpeg,.jpg image/jpeg
au聲音文件 .au audio/basic
MIDI音樂文件 mid,.midi audio/midi,audio/x-midi
RealAudio音樂文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
任意的二進制數據 application/octet-stream

 
5.Ertras屬性
 
  通過上面的這些項,識別問題,基本完美解決了,剩下一個重要的問題,就是傳參。Extras是用來做這個事情的,它是一個Bundle 類的對象,有一組可序列化的key/value對組成。每一個Action都會有與之對應的key和value類型約定,發起Intent的時候,需要按照要求把Data不能表示的額外參數放入Extras中。
6.Flags屬性
   能識別,有輸入,整個Intent基本就完整了,但還有一些附件的指令,需要放在Flags中帶過去。顧名思義,Flags是一個整形數,有一些列的標志 位構成,這些標志,是用來指明運行模式的。比如,你期望這個意圖的執行者,和你運行在兩個完全不同的任務中(或說進程也無妨吧...),就需要設置FLAG_ACTIVITY_NEW_TASK 的標志位。
7.Component屬性
    通常來說,"意圖"可分為顯示intent和隱式intent。Intent Filters它是用來描述一個Activity或 Serveice等組件,我們通過在組件AndroidManifest.xml中<intent-ilters/>元素中添加<action/>等屬性,以滿足期望能夠響應怎么樣的Intent,這種沒有指明要啟動組件名方式就稱之為隱式intent。當然,我們也可以使"意圖"實現啟動指定的組件,即稱之為顯示intent,主要通過Component屬性來實現。Intent的Component屬性需要接受一個ComponentName對象,這個對實現將要啟動指定組件的類名、類所在的包名綁定在intent上。
[java]  view plain  copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. ComponentName comp=new ComponentName(ComponentAttr.this,SecondaryActivity.class);   
  2. Intent intent=new Intent();  
  3. intent.setComponent( comp);//設置intent的Component屬性,指定"意圖"要啟動組件的包和類名  
  4. 注釋:第一句用於創建一個ComponentName對象,來指定包名和類型-這就可以唯一地確定一個組件類。  
 
四、Intent相關類
 
1.Activity類
   這里我們只需學習使用Intent啟動Activity組件將要用的的方法
 
void
startActivity(Intent intent)
作用:啟動Activity,具體啟動哪個Activity和怎么樣啟動由intent屬性決定
void
startActivityForResult(Intent intent, int requestCode)
作用:啟動Activity,並返回一個結果。當被啟動的Activity退出時,會調用 onActivityResult() 方法並向其傳入一個 requestCode參數,這個 requestCode參數為非負數(>0),作用是標志是哪個Activity組件發出的"意圖",需要注意的是如果 requestCode小於0時,這個方法的只能用於啟動一個Activity而不能返回值了。另外,Intent的action屬性設為能夠返回一個結果,如果設置為  Intent.ACTION_MAIN or  Intent.ACTION_VIEW,也是不能獲取結果的。
待寫:另外還有如何啟動Service、BroadcastReceiver組件的方法,這以后學到了再說吧。
2.Intent類
(1)構造函數
 
Intent():創建一個空的構造函數       Intent( Intent o)     :拷貝構造函數
 
Intent( String action)  :創建一個具有acion屬性的意圖對象
 
Intent( String action,  Uri uri):創建一個帶action屬性的意圖,接受一個Uri對象
 
Intent( Context packageContext,  Class<?> cls):創建一個已經指定組件的意圖
 
Intent( String action,  Uri uri,  Context packageContext,  Class<?> cls)
為一個指定的組件創建一個帶action和data屬性的意圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM