Android intent消息通知機制

Android intent消息通知機制 java

    一直想深刻分析研究android中的intent消息通知機制和binder機制,如今終於有機會了,在這裏我先經過網上查詢資料,看相關文獻,研究分析了android中的intent機制,最後將學到的東西整理以下,供你們學習參考。 android

   大部分移動設備平臺上的應用程序都運行在他們本身的沙盒中。他們彼此之間互相隔離,而且嚴格限制應用程序和原始組件之間的直接交互。咱們知道組件間交流是多麼的重要,做爲一個孤島沒有交流,必定毫無心義! 數據庫

   Android應用程序也是一個沙盒,可是他們可以使用Intent、BroadcastReceivers、Adapters、ContentProviders、Internet去突破他們的邊界互相交流。有交流還會和諧,因而可知這些交流手段有多重要。 數組

   咱們知道android應用程序的三大組件——Activities、Services、BroadcastReceiver(IntentReceiver),不一樣的活動(服務,廣播接收器)之間的交流便是經過消息觸發,這個消息就稱做意圖(Intent)。那麼這個消息是如何觸發的,如何傳遞的,如何響應的,在這裏咱們就藉機順着這條線,完全詳細地介紹一下Intent。 數據結構

   爲了以更容易理解,更清晰的形式介紹intent機制,現分兩篇文章介紹:理論篇和實例篇。 app

實例篇: ide

本篇的主要內容以下: 學習

•        一、概述 測試

•        二、Intent對象 this

•        2.一、組件名字

•        2.二、動做

•        2.三、數據

•        2.四、種類

•        2.五、附加信息

•        2.六、標誌

•        三、Intent解析

•        3.一、Intent過濾器

•        3.1.一、動做檢測

•        3.1.二、種類檢測

•        3.1.三、數據檢測

•        3.二、通用狀況

•        3.三、使用intent匹配

一、概述

   一個應用程序的三個核心組件——activities、services、broadcastreceivers,都是經過叫作intents的消息觸發激活。Intent消息是android中一種同一或不一樣應用程序中的組件之間延遲運行時綁定的消息通知機制。intent自己(一個Intent對象)是一個被動的數據結構,保存一個將要執行的操做的抽象描述,或在廣播的狀況下,一般是某事已經發生且正在宣告。

   具體地說:Intent負責對應用中一次操做的動做、動做涉及數據、附加數據進行描述,Android則根據此Intent的描述,負責找到對應的組件,將Intent傳遞給調用的組件,並完成組件的調用。所以,Intent在這裏起着一個媒體中介的做用,專門提供組件互相調用的相關信息,實現調用者與被調用者之間的解耦。

   對於這三種組件,都有獨立的傳送intent的機制:

  (1)Activity:一個intent對象傳遞給Context.startActivity()或Activity.startActivityForRestult()去啓動一個活動或使一個已存在的活動去作新的事情。

  (2)Service:一個intent對象傳遞給Context.startService()去初始化一個service或傳遞一個新的指令給正在運行的service。相似的,一個intent能夠傳遞給Context.bindService()去創建調用組件和目標服務之間的鏈接。

   (3)BroadcastReceiver:一個intent對象傳遞給任何廣播方法(如Context.sendBroadcast(),Context.sendOrderedBroadcast(),Context.sendStickyBroadcast()),都將傳遞到全部感興趣的廣播接收者。

   在每種狀況下,Android系統查找合適的activity、service、broadcastreceivers來響應意圖,若是有必要的話,先初始化他們。這些消息系統之間沒有重疊,即廣播意圖僅會傳遞給廣播接收者,而不會傳遞活動或服務,反之亦然。

   下面首先描述intent對象,而後介紹Android將intent映射到相應組件的規則——如何解決哪一個組件應該接收intent消息。對於沒有指定目標組件名字的intent,這個處理過程包括按照intentfilters匹配每一個潛在的目標對象。

二、Intent對象

   一個Intent對象是一個捆信息,包含對intent有興趣的組件的信息(如要執行的動做和要做用的數據)、Android系統有興趣的信息(如處理intent組件的分類信息和如何啓動目標活動的指令)。下面列出它的主要信息:

2.一、組件名字

   處理intent的組件的名字。這個字段是一個ComponentName對象——是目標組件的徹底限定類名(如"com.example.project.app.FreneticActivity")和應用程序所在的包在清單文件中的名字(如"com.example.project")的組合。其中組件名字中的包部分沒必要必定和清單文件中的包名同樣。組件名字是可選的,若是設置了組件名字,intent對象傳遞到指定類的實例;若是沒有設置,Android使用intent中的其它隱式信息來定位合適的目標組件(見下面的Intent解析)。

   組件的名字經過setComponent(),setClass()或setClassName()設置,經過getComponent()讀取。

2.二、動做

   一個字符串命名的動做將被執行,或在廣播intent中,已發生動做且正被報告。Intent類定義了一些動做常量,以下:

Constant

Target component

Action

ACTION_CALL

activity

Initiate a phone call.

ACTION_EDIT

activity

Display data for the user to edit.

ACTION_MAIN

activity

Start up as the initial activity of a task, withno data input and no returned output.

ACTION_SYNC

activity

Synchronize data on a server with data on themobile device.

ACTION_BATTERY_LOW

broadcast receiver

A warning that the battery is low.

ACTION_HEADSET_PLUG

broadcast receiver

A headset has been plugged into the device, orunplugged from it.

ACTION_SCREEN_ON

broadcast receiver

The screen has been turned on.

ACTION_TIMEZONE_CHANGED

broadcast receiver

The setting for the time zone has changed.

查看更多的動做請參考Intent類。其它的動做定義在AndroidAPI中,咱們還能夠定義本身的動做字符串,而後在咱們的應用程序中激活組件。自定義動做字符串應該包含應用程序包名前綴,如"com.example.project.SHOW_COLOR"。

   動做很大程度上決定了剩下的intent如何構建,特別是數據(data)和附加(extras)字段,就像一個方法名決定了參數和返回值。正是這個緣由,應該儘量明確指定動做,並緊密關聯到其它intent字段。換句話說,你應該定義你的組件可以處理的Intent對象的整個協議,而不只僅是單獨地定義一個動做。

   一個intent對象的動做經過setAction()方法設置,經過getAction()方法讀取。

2.三、數據

   數據(data)是將做用於其上的數據的URI和數據的MIME類型。不一樣的動做有不一樣的數據規格。例如,若是動做字段是ACTION_EDIT,數據字段包含將顯示用於編輯的文檔的URI;若是動做是ACTION_CALL,數據字段將是一個tel:URI和將撥打的號碼;若是動做是ACTION_VIEW,數據字段是一個http:URI,接收活動將被調用去下載和顯示URI指向的數據。

   當匹配一個intent到一個可以處理該數據的組件,一般知道數據的類型(它的MIME類型)和它的URI很重要。例如,一個組件可以顯示圖像數據,不該該被調用去播放一個音頻文件。在許多狀況下,數據類型可以從URI中推測,特別是content:URIs,它表示位於設備上的數據且被內容提供者(contentprovider)控制。可是類型也可以顯示地設置,setData()方法指定數據的URI,setType()指定MIME類型,setDataAndType()指定數據的URI和MIME類型。經過getData()讀取URI,getType()讀取類型。

2.四、種類

   此外,還包含關於應該處理intent的組件類型信息。能夠在一個Intent對象中指定任意數量的種類描述。Intent類定義的一些種類常量,以下這些:

Constant

Meaning

CATEGORY_BROWSABLE

The target activity can be safely invoked by thebrowser to display data referenced by a link — for example, animage or an e-mail message.

CATEGORY_GADGET

The activity can be embedded inside of anotheractivity that hosts gadgets.

CATEGORY_HOME

The activity displays the home screen, the firstscreen the user sees when the device is turned on or when the HOMEkey is pressed.

CATEGORY_LAUNCHER

The activity can be the initial activity of atask and is listed in the top-level application launcher.

CATEGORY_PREFERENCE

The target activity is a preference panel.

更多的種類常量請參考Intent類。

   下面是一些關於種類的調用方法:addCategory()方法添加一個種類到Intent對象中,removeCategory()方法刪除一個以前添加的種類,getCategories()方法獲取Intent對象中的全部種類。

2.五、附加信息

   額外的鍵值對信息應該傳遞到組件處理intent。就像動做關聯的特定種類的數據URIs,也關聯到某些特定的附加信息。例如,一個ACTION_TIMEZONE_CHANGEintent有一個"time-zone"的附加信息,標識新的時區,ACTION_HEADSET_PLUG有一個"state"附加信息,標識頭部如今是否塞滿或未塞滿;有一個"name"附加信息,標識頭部的類型。若是你自定義了一個SHOW_COLOR動做,顏色值將能夠設置在附加的鍵值對中。

   Intent對象有一系列的put…()方法用於插入各類附加數據和一系列的get…()用於讀取數據。這些方法與Bundle對象的方法相似,實際上,附加信息能夠做爲一個Bundle使用putExtras()和getExtras()安裝和讀取。關於Bundle的用法查閱相關資料。

2.六、標誌

   Intent對象中有各類各樣的標誌,許多指示Android系統如何去啓動一個活動(例如,活動應該屬於那個任務)和啓動以後如何對待它(例如,它是否屬於最近的活動列表)。全部這些標誌都定義在Intent類中。

三、Intent解析

   Intent能夠分爲兩組:

  (1)顯式intent:經過名字指定目標組件。由於開發者一般不知道其它應用程序的組件名字,顯式intent一般用於應用程序內部消息,如一個活動啓動從屬的服務或啓動一個姐妹活動。

  (2)隱式intent:並不指定目標的名字(組件名字字段是空的)。隱式intent常常用於激活其它應用程序中的組件。

   顯示intent傳遞:Android顯式傳遞一個intent到一個指定目標類的實例。Intent對象中只用組件名字內容去決定哪一個組件應該得到這個intent,而不用其餘內容。

   隱式intent傳遞:須要另一種不一樣的策略。因爲缺省指定目標,Android系統必須查找一個最適合的組件(一些組件)去處理intent——一個活動或服務去執行請求動做,或一組廣播接收者去響應廣播聲明。這是經過比較Intent對象的內容和intent過濾器(intentfilters)來完成的。每一個intent過濾器都關聯到一個潛在的接收intent的組件。過濾器聲明組件的能力和界定它能處理的intents,它們打開接收組件聲明的intent類型的隱式intents。若是一個組件沒有任何intent過濾器,它僅能接收顯示的intents,而聲明瞭intent過濾器的組件能夠接收顯示和隱式的intents。

   注意:只有當一個Intent對象的下面三個方面都符合一個intent過濾器:action、data(包括URI和數據類型)、category,才被考慮。附加信息和標誌在解析哪一個組件接收intent中不起做用。

3.一、Intent過濾器

   活動、服務、廣播接收者爲了告知系統可以處理哪些隱式intent,它們能夠有一個或多個intent過濾器。每一個過濾器描述組件的一種能力,即樂意接收的一組intent。實際上,它篩掉了不想要的intents,也僅僅是不想要的隱式intents。一個顯式intent老是可以傳遞到它的目標組件,無論它包含什麼,不考慮過濾器。可是一個隱式intent,僅當它可以經過組件的過濾器之一纔可以傳遞給它。

   一個組件可以作的每一工做,都有獨立的過濾器。例如,記事本中的NoteEditer活動有兩個過濾器,一個是啓動一個指定的記錄,用戶能夠查看和編輯;另外一個是啓動一個新的、空的記錄,用戶可以填充並保存。一個intent過濾器是一個IntentFilter類的實例。由於Android系統在啓動一個組件以前必須知道它的能力,要注意的是:intent過濾器一般不在java代碼中設置,而是在應用程序的清單文件(AndroidManifest.xml)中以<intent-filter>元素設置。但有一個例外,廣播接收者的過濾器經過調用Context.registerReceiver()動態地註冊,它直接建立一個IntentFilter對象。

   每個過濾器都有對應於Intent對象的動做、數據、種類的字段。過濾器要檢測隱式intent的全部這三個字段,其中任何一個失敗,Android系統都不會傳遞intent給組件。然而,由於一個組件能夠有多個intent過濾器,一個intent通不過組件的過濾器檢測,其它的過濾器可能經過檢測。

3.1.一、動做檢測

   清單文件中的<intent-filter>元素以<action>子元素列出動做,例如:

<intent-filter . . .>

   <actionandroid:name="com.example.project.SHOW_CURRENT"/>

   <actionandroid:name="com.example.project.SHOW_RECENT"/>

   <actionandroid:name="com.example.project.SHOW_PENDING"/>

    . . .

</intent-filter>

像例子所展現,雖然一個Intent對象僅是單個動做,可是一個過濾器能夠列出不止一個。這個列表不可以爲空,一個過濾器必須至少包含一個<action>子元素,不然它將阻塞全部的intents。要經過檢測,Intent對象中指定的動做必須匹配過濾器的動做列表中的一個。若是對象或過濾器沒有指定一個動做,結果將以下:

(1)若是過濾器沒有指定動做,沒有一個Intent將匹配,全部的intent將檢測失敗,即沒有intent可以經過過濾器。

(2)若是Intent對象沒有指定動做,將自動經過檢查(只要過濾器至少有一個過濾器,不然就是上面的狀況了)

3.1.二、種類檢測

   相似的,清單文件中的<intent-filter>元素以<category>子元素列出種類,例如:

<intent-filter . . .>

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

   <categoryandroid:name="android.intent.category.BROWSABLE"/>

    . . .

</intent-filter>

   注意:本文前面兩個表格列舉的動做和種類常量並不在清單文件中使用,而是使用全字符串值。例如,例子中所示的"android.intent.category.BROWSABLE"字符串對應於本文前面提到的BROWSABLE常量。相似的,"android.intent.action.EDIT"字符串對應於ACTION_EDIT常量。

   對於一個intent要經過種類檢測,intent對象中的每一個種類必須匹配過濾器中的一個。即過濾器可以列出額外的種類,可是intent對象中的種類都必須可以在過濾器中找到,只要有一個種類在過濾器列表中沒有,就算種類檢測失敗。所以,原則上若是一個intent對象中沒有種類(即種類字段爲空)應該老是經過種類測試,而無論過濾器中有什麼種類。可是有個例外,Android對待全部傳遞給Context.startActivity()的隱式intent好像它們至少包含"android.intent.category.DEFAULT"(對應CATEGORY_DEFAULT常量)。所以,活動想要接收隱式intent必需要在intent過濾器中包含"android.intent.category.DEFAULT"。

   注意:"android.intent.action.MAIN" 和"android.intent.category.LAUNCHER"設置,它們分別標記活動開始新的任務和帶到啓動列表界面。它們能夠包含"android.intent.category.DEFAULT"到種類列表,也能夠不包含。

3.1.三、數據檢測

   相似的,清單文件中的<intent-filter>元素以<data>子元素列出數據,例如:

<intent-filter . . .>

   <data android:mimeType="video/mpeg"android:scheme="http" . . . />

   <data android:mimeType="audio/mpeg"android:scheme="http" . . . />

    . . .

</intent-filter>

每一個<data>元素指定一個URI和數據類型(MIME類型)。它有四個屬性scheme、host、port、path對應於URI的每一個部分:scheme://host:port/path。例以下面的URI:「content://com.example.project:200/folder/subfolder/etc」,scheme是content,host是"com.example.project",port是200,path是"folder/subfolder/etc"。host和port一塊兒構成URI的憑據(authority),若是host沒有指定,port也被忽略。這四個屬性都是可選的,但它們之間並不都是徹底獨立的。要讓authority有意義,scheme必須也要指定。要讓path有意義,scheme和authority也都必需要指定。

   當比較intent對象和過濾器的URI時,僅僅比較過濾器中出現的URI屬性。例如,若是一個過濾器僅指定了scheme,全部有此scheme的URIs都匹配過濾器;若是一個過濾器指定了scheme和authority,但沒有指定path,全部匹配scheme和authority的URIs都經過檢測,而無論它們的path;若是四個屬性都指定了,要都匹配才能算是匹配。然而,過濾器中的path能夠包含通配符來要求匹配path中的一部分。

   <data>元素的type屬性指定數據的MIME類型。Intent對象和過濾器均可以用"*"通配符匹配子類型字段,例如"text

    @Override

    publicvoid onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

 

        IntentorgIntent=getIntent();

        UriqueryUri=orgIntent.getData();        

        finalCursor c = managedQuery(queryUri,

                null,

                null,

                null,

                null);

        

        String[]fromColumns=newString[]{ContactsContract.Contacts.DISPLAY_NAME};

        int[]toLayoutIDs = new int[] { R.id.itemTextView};

        SimpleCursorAdapteradapter = new SimpleCursorAdapter(this,

                R.layout.listitemlayout,c, fromColumns, toLayoutIDs);

        ListViewlv = (ListView) findViewById(R.id.contactListView);

        lv.setAdapter(adapter);

        lv.setOnItemClickListener(newOnItemClickListener() {

            @Override

            publicvoidonItemClick(AdapterView<?> parent,View view, int pos,

                    longid) {

                c.moveToPosition(pos);    

                introwId =c.getInt(c.getColumnIndexOrThrow(ContactsContract.Contacts._ID));

                UrioutURI =Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString()+ rowId);

                IntentoutData = new Intent();

                outData.setData(outURI);

                setResult(Activity.RESULT_OK,outData);

                finish();

            }

        });

    }

}

 

STEP四、解析通信錄返回的數據

   從通信錄活動返回以後,咱們從返回的Intent中提取數據並填充到填寫電話號碼的EditView中。代碼主要以下:

@Override

public voidonActivityResult(int reqCode, int resCode, Intentdata) {

    super.onActivityResult(reqCode,resCode, data);

 

    switch(reqCode) {

    case(PICK_CONTACT): {

        if(resCode == Activity.RESULT_OK) {

            Stringname;                

            UricontactData = data.getData();

            Cursorc = managedQuery(contactData, nullnull,nullnull);

            c.moveToFirst();

            name=c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

            TextViewtv;

            tv= (TextView)findViewById(R.id.edtPhoneNo);

            tv.setText(name);

        }

        break;

    }

    }

}

 

STEP五、在清單文件AndroidManifest.xml中註冊通信錄活動和讀取Contact數據庫的權限

   主要工做基本作完了,如今咱們只須要註冊通信錄活動和讀取Contact數據的權限了。完整的清單文件代碼以下:

<?xml version="1.0"encoding="utf-8"?>

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

    package="skynet.com.cnblogs.www"android:versionCode="1"

    android:versionName="1.0">

    <application>

        <activityandroid:name=".TextMessage"android:label="@string/app_name">

            <intent-filter>

                <actionandroid:name="android.intent.action.MAIN"/>

                <categoryandroid:name="android.intent.category.LAUNCHER"/>

            </intent-filter>

        </activity>

        <activityandroid:name=".ContactPick"android:label="@string/app_name">

            <actionandroid:name="android.intent.action.PICK"/>

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

        </activity>

    </application>

    <uses-permissionandroid:name="android.permission.SEND_SMS"/>

    <uses-permissionandroid:name="android.permission.READ_CONTACTS"/>

</manifest>

   注意通信錄活動的IntentFilters,它的action是android.intent.action.PICK;category是android.intent.category.DEFAULT。如今咱們分析一下這個IntentFilter:

•      <action android:name="android.intent.action.PICK"/>:使用戶可以能夠在通信錄列表中選擇一個,而後將選擇的聯繫人的 URL返回給調用者。

•      <categoryandroid:name="android.intent.category.DEFAULT"/>:這是默認的category,若是不知道category系統會自動加上。這個屬性是讓使其可以被像Context.startActivity()等找到。要說明的的是,若是列舉了多個category,這個活動僅會去處理那些Intent中都包含了全部列舉的category的組件。

   咱們還能夠在清單文件中看到TextMessage活動的Intent Filter:

<intent-filter>

    <actionandroid:name="android.intent.action.MAIN"/>

    <categoryandroid:name="android.intent.category.LAUNCHER"/>

</intent-filter>

    它指定TextMessage活動是這個程序的入口,而且TextMessage會列舉在Launcher即啓動列表中。


總結

   咱們用發短信中選擇聯繫人的例子說明Intent和Intent Filter,這裏體現了兩個活動之間如何經過Intent和IntentFilter來交互,這也是咱們在編寫Android應用程序的時候常常遇到了。本文除了上述的主要內容以外,還涉及別的知識點,下面列舉幾個我的認爲比較有用的知識點:

•    Curor類它跟咱們平時用的數據庫中的遊標相似,它提供了對從數據庫返回的結果的隨機讀寫操做。如咱們例子中用到的,經過managedQuery方法查詢數據庫並返回結果,而後利用Cursor對它進行操做。下面介紹Cursor類的幾個方法(咱們例子中用到的,更多的方法請自行查閱相關資料):

•      public abstract int getColumnIndexOrThrow (StringcolumnName):返回給定列名的索引(注意:從0開始的),或者當列名不存在時拋出llegalArgumentException異常;

•      public abstract boolean moveToFirst():移動到第一行。若是Cursor爲空,則返回FALSE

•      public abstract boolean moveToPosition (intposition):將遊標移動到一個指定的位置,它的範圍在-1 <= position<= count。若是position位置不可達,返回FALSE

•      managedQuery方法:根據指定的URI路徑信息返回包含特定數據的Cursor對象,應用這個方法可使Activity接管返回數據對象的生命週期。參數:

URI: Content Provider 須要返回的資源索引

Projection: 用於標識有哪些columns須要包含在返回數據中

Selection: 做爲查詢符合條件的過濾參數,相似於SQL語句中Where以後的條件判斷

SelectionArgs: 同上

SortOrder: 用於對返回信息進行排序

•      SimpleCursorAdapter容許你綁定一個遊標的列到ListView上,並使用自定義的layout顯示每一個項目。SimpleCursorAdapter的建立,須要傳入當前的上下文、一個layout資源,一個遊標和兩個數組:一個包含使用的列的名字,另外一個(相同大小)數組包含View中的資源ID,用於顯示相應列的數據值。

相關文章
相關標籤/搜索