由于android系統(tǒng)中應(yīng)用程序之間不能共享內(nèi)存。
因此佳晶,在不同應(yīng)用程序之間交互數(shù)據(jù)(跨進(jìn)程通訊)就稍微麻煩一些愚屁。系統(tǒng)提供了4種跨進(jìn)程通訊的方式。對(duì)應(yīng)于應(yīng)用程序四大組件:
Activity
Content Provider
Broadcast
Service
其中Activity可以跨進(jìn)程調(diào)用其他應(yīng)用程序的Activity伟恶;
Content Provider可以跨進(jìn)程訪問其他應(yīng)用程序中的數(shù)據(jù)(以Cursor對(duì)象形式返回),也可以對(duì)其進(jìn)行增毅该、刪博秫、改操作潦牛;Broadcast可以向android系統(tǒng)中所有應(yīng)用程序發(fā)送廣播,而需要跨進(jìn)程通訊的應(yīng)用程序可以監(jiān)聽這些廣播挡育;
Service和Content Provider類似巴碗,也可以訪問其他應(yīng)用程序中的數(shù)據(jù),但不同的是即寒,Content Provider返回的是Cursor對(duì)象橡淆,而Service返回的是Java對(duì)象,這種可以跨進(jìn)程通訊的服務(wù)叫AIDL服務(wù)蒿叠。
方式一:訪問其他應(yīng)用程序的Activity
Activity既可以在進(jìn)程內(nèi)(同一個(gè)應(yīng)用程序)訪問明垢,也可以跨進(jìn)程訪問。
在同一個(gè)應(yīng)用程序中訪問Activity市咽,需要指定Context對(duì)象和Activity的Class對(duì)象痊银,代碼如下:
Intent intent = new ?Intent(this , Test.class );
startActivity(intent);
Activity的跨進(jìn)程訪問與進(jìn)程內(nèi)訪問略有不同。雖然它們都需要Intent對(duì)象施绎,但跨進(jìn)程訪問并不需要指定Context對(duì)象和Activity的Class對(duì)象溯革,而需要指定的是要訪問的Activity所對(duì)應(yīng)的Action(一個(gè)字符串)。有些Activity還需要指定一個(gè)Uri(通過Intent構(gòu)造方法的第2個(gè)參數(shù)指定)谷醉。
在android系統(tǒng)中有很多應(yīng)用程序提供了可以跨進(jìn)程訪問的Activity致稀,例如,下面的代碼可以直接調(diào)用撥打電話的Activity俱尼。
Intent callIntent = new ?Intent(Intent.ACTION_CALL, Uri.parse("tel://13888888888" );
startActivity(callIntent);
執(zhí)行上面的代碼后抖单,系統(tǒng)會(huì)自動(dòng)撥號(hào).
在調(diào)用撥號(hào)程序的代碼中使用了一個(gè)Intent.ACTION_CALL常量,該常量的定義如下:
public ?static ?final ?String ACTION_CALL = "android.intent.action.CALL" ;
這個(gè)常量是一個(gè)字符串常量遇八,也是我們?cè)谶@節(jié)要介紹的跨進(jìn)程調(diào)用Activity的關(guān)鍵矛绘。如果在應(yīng)用程序中要共享某個(gè)Activity,需要為這個(gè)Activity指定一個(gè)字符串ID刃永,也就是Action货矮。也可以將這個(gè)Action看做這個(gè)Activity的key。在其他的應(yīng)用程序中只要通過這個(gè)Action就可以找到與Action對(duì)應(yīng)的Activity斯够,并通過startActivity方法來啟動(dòng)這個(gè)Activity囚玫。
下面先來看一下如何將應(yīng)用程序的Activity共享出來,讀者可按如下幾步來共享Activity:
1. ?在AndroidManifest.xml文件中指定Action读规。指定Action要使用標(biāo)簽抓督,并在該標(biāo)簽的android:name屬性中指定Action
2. ?在AndroidManifest.xml文件中指定訪問協(xié)議。在指定Uri(Intent類的第2個(gè)參數(shù))時(shí)需要訪問協(xié)議束亏。訪問協(xié)議需要使 用標(biāo)簽的android:scheme屬性來指定铃在。如果該屬性的值是“mdm”,那么Uri就應(yīng)該是“mdm://Uri的主體 部分”枪汪,也就是說涌穆,訪問協(xié)議是Uri的開頭部分。
3. ?通過getIntent().getData().getHost()方法獲得協(xié)議后的Uri的主體部分雀久。這個(gè)Host只是個(gè)稱謂宿稀,并不一定是主機(jī)名。讀者可以將其看成是任意的字符串赖捌。
4. ?從Bundle對(duì)象中獲得其他應(yīng)用程序傳遞過來的數(shù)據(jù)祝沸。
5. ?這一步當(dāng)然是獲得數(shù)據(jù)后做進(jìn)一步的處理了。至于如何處理這些數(shù)據(jù)越庇,就得根據(jù)具體的需求決定了罩锐。
下面來根據(jù)這些步驟共享一個(gè)Activity。首先建立一個(gè)android工程(ActionActivity)卤唉,工程的主Activity是Main涩惑。在 本例中我們會(huì)共享這個(gè)Main類。首先打開AndroidManifest.xml文件桑驱,添加一個(gè)標(biāo)簽竭恬,并重新定義了Main的相應(yīng)屬性。AndroidManifest.xml文件的內(nèi)容如下:
在配置AndroidManifest.xml時(shí)要注意熬的,不能在同一個(gè)<activity>中配置多個(gè)動(dòng)作痊硕,否則會(huì)覆蓋MAIN動(dòng)作以使該程序無法正常啟動(dòng)(雖然其他應(yīng)用程序調(diào)用Main是正常的).
標(biāo)簽指定了Url的協(xié)議,則在調(diào)用Main時(shí)需要使用如下的URL:
mdm://任意字符串
一般標(biāo)簽的android:name屬性值可以設(shè)成android.intent.category.DEFAULT,這個(gè)必須要設(shè)置,不然無法訪問到押框。
下面來看看如何在Main類的onCreate方法中獲得其他應(yīng)用程序傳遞過來的數(shù)據(jù)岔绸。
從上面的程序可以看出,首先通過getIntent().getData()來判斷其他的應(yīng)用程序是否傳遞了Uri(getData方法返回了一個(gè)Uri 對(duì)象)橡伞。
下面來看一下其他的應(yīng)用程序是如何調(diào)用MainActivity的盒揉。新建一個(gè)android工程(InvokeActivity),并添加一個(gè)按鈕骑歹,按鈕的單擊事件方法代碼如下:
從本節(jié)的介紹可以看出预烙,跨進(jìn)程訪問Activity(訪問其他應(yīng)用程序中的Activity)主要是通過一個(gè)Action來完成的,如果要傳遞數(shù)據(jù)道媚,還需 要指定一個(gè)Uri扁掸。當(dāng)然,傳遞數(shù)據(jù)也可以通過Intent來完成最域。傳遞數(shù)據(jù)的過程可以是雙向的谴分。如果要想從調(diào)用的Activity中返回?cái)?shù)據(jù),就需要使用startActivityForResult方法來啟動(dòng)Activity了镀脂。
方式二:Content Provider
Android應(yīng)用程序可以使用文件或SqlLite數(shù)據(jù)庫來存儲(chǔ)數(shù)據(jù)牺蹄。Content Provider提供了一種在多個(gè)應(yīng)用程序之間數(shù)據(jù)共享的方式(跨進(jìn)程共享數(shù)據(jù))。應(yīng)用程序可以利用Content Provider完成下面的工作
1. 查詢數(shù)據(jù)
2. 修改數(shù)據(jù)
3. 添加數(shù)據(jù)
4. 刪除數(shù)據(jù)
雖然Content Provider也可以在同一個(gè)應(yīng)用程序中被訪問薄翅,但這么做并沒有什么意義沙兰。Content Provider存在的目的向其他應(yīng)用程序共享數(shù)據(jù)和允許其他應(yīng)用程序?qū)?shù)據(jù)進(jìn)行增氓奈、刪、改操作鼎天。
Android系統(tǒng)本身提供了很多Content Provider舀奶,例如,音頻斋射、視頻育勺、聯(lián)系人信息等等。我們可以通過這些Content Provider獲得相關(guān)信息的列表罗岖。這些列表數(shù)據(jù)將以Cursor對(duì)象返回涧至。因此,從Content Provider返回的數(shù)據(jù)是二維表的形式桑包。
對(duì)于訪問Content Provider的程序南蓬,需要使用ContentResolver對(duì)象。該對(duì)象需要使用getContentResolver方法獲得哑了,代碼如下:
ContentResolver cr = getContentResolver();
與Activity一樣蓖康,Content Provider也需要與一個(gè)URI對(duì)應(yīng)。每一個(gè)Content Provider可以控制多個(gè)數(shù)據(jù)集垒手,在這種情況下蒜焊,每一個(gè)數(shù)據(jù)集會(huì)對(duì)應(yīng)一個(gè)單獨(dú)的URI。所有的URI必須以“content://”開頭科贬。
為了程序更容易維護(hù)泳梆,也為了簡化程序代碼,一般將URI定義成一個(gè)常量榜掌。例如优妙,下面的常量表示系統(tǒng)的聯(lián)系人電話號(hào)碼。
android.provider.Contacts.Phones.CONTENT_URI
下面來看一下編寫Content Provider的具體步驟憎账。
1. ?編寫一個(gè)繼承于android.content.ContentProvider的子類套硼。該類是ContentProvider的核心類。在該類中會(huì)實(shí)現(xiàn)query胞皱、insert邪意、update及delete方法。實(shí)際上調(diào)用ContentResolver類的這4個(gè)方法就是調(diào)用ContentProvider類中與之要對(duì)應(yīng)的方法反砌。在本文中只介紹query雾鬼。至于insert、update宴树、delete和query的用法類 似策菜。也是通過Uri傳遞參數(shù),然后在這些方法中接收這些參數(shù),并做進(jìn)一步地處理又憨。
2. ?在AndroidManifest.xml文件中配置ContentProvider翠霍。要想唯一確定一個(gè)ContentProvider,需要指定這個(gè)ContentProvider的URI蠢莺,除此之外壶运,還需要指定URI所對(duì)應(yīng)的ContentProvider類。這有些象Servlet的定義浪秘,除了要 指定Servlet對(duì)應(yīng)的Web地址,還要指定這個(gè)地址所對(duì)應(yīng)的Servlet類埠况。
現(xiàn)在來看一下Uri的具體格式耸携,先看一下如圖5所示的URI。
下面對(duì)圖5所示的URI的4個(gè)部分做一下解釋辕翰。
A:Content Provider URI的固定前綴夺衍,也就是說,所有的URI必須以content://開頭喜命。
B:URI中最重要的部分沟沙。該部分是Content Provider的唯一標(biāo)識(shí)。對(duì)于第三方應(yīng)用程序來說壁榕,該部分最后使用完整的類名(包名+類名)矛紫,以確保URI的唯一性。該部分需要在AndroidManifest.xml文件中標(biāo)簽中定義牌里,代碼如下:
C:這部分是URI的路徑(path)颊咬。表示URI中各種被請(qǐng)求的數(shù)據(jù)。這部分是可選的牡辽, 如果Content Provider僅僅提供一種請(qǐng)求的數(shù)據(jù)喳篇,那么這部分可以省略。如果Content Provider要提供多種請(qǐng)求數(shù)據(jù)态辛。就需要添加多個(gè)路徑麸澜,甚至是子路徑。例如奏黑,“l(fā)and/bus”炊邦、“l(fā)and/train”、“sea/ship” 就指定了3種可能提供的數(shù)據(jù)熟史。
D:這部分也是可選的铣耘。如果要傳遞一個(gè)值給Content Provider,可以通過這部分傳遞以故。當(dāng)然蜗细,如果不需要傳值,這部分也可以省略,省略后的URI如下所示:
content://com.example.transportationprovider/trains
定義一個(gè)類繼承ContentProvider
調(diào)用查詢接口代碼:
Uri CONTENT_URI = Uri.parse("content://com.polysaas.mcm/media_doc")
Cursor localCursor =contentResolver.query(CONTENT_URI, null, null, null, null);
待續(xù).......