四種跨進(jìn)程通信方式

由于android系統(tǒng)中應(yīng)用程序之間不能共享內(nèi)存淹办。因此眉枕,在不同應(yīng)用程序之間交互數(shù)據(jù)(跨進(jìn)程通訊)就稍微麻煩一些。在android SDK中提供了4種用于跨進(jìn)程通訊的方式怜森。這4種方式正好對(duì)應(yīng)于android系統(tǒng)中4種應(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ì)象形式返回),當(dāng)然想许,也可以對(duì)其他應(yīng)用程序的數(shù)據(jù)進(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ù)。

完整示例請(qǐng)參閱本文提供的源代碼壁公。

方式一:訪問其他應(yīng)用程序的Activity

Activity既可以在進(jìn)程內(nèi)(同一個(gè)應(yīng)用程序)訪問感论,也可以跨進(jìn)程訪問。如果想在同一個(gè)應(yīng)用程序中訪問Activity紊册,需要指定Context對(duì)象和Activity的Class對(duì)象比肄,代碼如下:

Intent intent =newIntent(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 =newIntent(Intent.ACTION_CALL, Uri.parse("tel:12345678");

startActivity(callIntent);

執(zhí)行上面的代碼后嘹害,系統(tǒng)會(huì)自動(dòng)撥號(hào),界面如圖1所示丁稀。

在調(diào)用撥號(hào)程序的代碼中使用了一個(gè)Intent.ACTION_CALL常量吼拥,該常量的定義如下:

publicstaticfinalString 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屬性來指定攻臀。如果該屬性的值是“abc”焕数,那么Uri就應(yīng)該是“abc://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è)中配置多個(gè)動(dòng)作,否則會(huì)覆蓋MAIN動(dòng)作以使該程序無法正常啟動(dòng)(雖然其他應(yīng)用程序調(diào)用Main是正常的)邓线。

從上面的代碼可以看出淌友,標(biāo)簽的android:name屬性值是 net.blogjava.mobile.MYACTION,這就是Main自定義的動(dòng)作骇陈。標(biāo)簽指定了Url的協(xié)議震庭。如果指定 了標(biāo)簽的android:scheme屬性值(info),則在調(diào)用Main時(shí)需要使用如下的URL:

info://任意字符串

一般標(biāo)簽的android:name屬性值可以設(shè)成android.intent.category.DEFAULT你雌。

下面來看看如何在Main類的onCreate方法中獲得其他應(yīng)用程序傳遞過來的數(shù)據(jù)器联。

packagenet.blogjava.mobile.actionactivity;

... ...publicclassMainextendsActivityimplementsOnClickListener

{privateEditText editText;

@OverridepublicvoidonClick(View view)

{//單擊按鈕,會(huì)顯示文本框中的內(nèi)容(以Toast信息框形式顯示)Toast.makeText(this, editText.getText().toString(), Toast.LENGTH_LONG)

.show();

}

@OverridepublicvoidonCreate(Bundle savedInstanceState)

{super.onCreate(savedInstanceState);

setContentView(R.layout.main);

Button button=(Button) findViewById(R.id.button);

button.setOnClickListener(this);

editText=(EditText) findViewById(R.id.edittext);//獲得其他應(yīng)用程序傳遞過來的數(shù)據(jù)if(getIntent().getData() !=null)

{//獲得Host婿崭,也就是info://后面的內(nèi)容String host =getIntent().getData().getHost();

Bundle bundle=getIntent().getExtras();//其他的應(yīng)用程序會(huì)傳遞過來一個(gè)value值拨拓,在該應(yīng)用程序中需要獲得這個(gè)值String value = bundle.getString("value");//將Host和Value組合在一下顯示在EditText組件中editText.setText(host + ":" +value);//調(diào)用了按鈕的單擊事件,顯示Toast信息提示框onClick(button);

}

}

}

從上面的程序可以看出氓栈,首先通過getIntent().getData()來判斷其他的應(yīng)用程序是否傳遞了Uri(getData方法返回了一個(gè)Uri 對(duì)象)渣磷。如果運(yùn)行該程序,Uri為null授瘦,因此醋界,不會(huì)執(zhí)行if語句里面的代碼。當(dāng)其他的應(yīng)用程序傳遞了Uri對(duì)象后提完,系統(tǒng)會(huì)執(zhí)行if語句里面的代碼形纺。當(dāng) 運(yùn)行ActionActivity后,在文本框中輸入“Running”氯葬,單擊“顯示文本框的內(nèi)容”按鈕挡篓,會(huì)顯示如圖2所示的Toast提示信息框婉陷。

下面來看一下其他的應(yīng)用程序是如何調(diào)用ActionActivity中的Main帚称。新建一個(gè)android工程(InvokeActivity),并添加一個(gè)按鈕楼吃,按鈕的單擊事件方法代碼如下:

publicvoidonClick(View view)

{//需要使用Intent類的第2個(gè)參數(shù)指定UriIntent intent =newIntent("net.blogjava.mobile.MYACTION", Uri

.parse("info://調(diào)用其他應(yīng)用程序的Activity"));//設(shè)置value屬性值intent.putExtra("value", "調(diào)用成功");//調(diào)用ActionActivity中的MainstartActivity(intent);

}

在運(yùn)行InvokeActivity之前躬窜,先要運(yùn)行ActionActivity以便在android模擬器中安裝該程序。然后單擊InvokeActivity中的按鈕,就會(huì)顯示如圖3所示的效果。

當(dāng)然,也可以使用startActivityForResult方法來啟動(dòng)其他應(yīng)用程序的Activity,以便獲得Activity的返回值。例如,可以將ActionActivity中Main類的onClick代碼修改為下面的形式养盗。

publicvoidonClick(View view)

{

Toast.makeText(this, editText.getText().toString(), Toast.LENGTH_LONG).show();

Intent intent=newIntent();//設(shè)置要返回的屬性值intent.putExtra("result", editText.getText().toString());//設(shè)置返回碼和Intent對(duì)象setResult(2, intent);//關(guān)閉Activityfinish();

}

然后在InvokeActivity中使用下面的代碼來調(diào)用Main。

intent =newIntent("net.blogjava.mobile.MYACTION", Uri

.parse("info://調(diào)用其他應(yīng)用程序的Activity"));//傳遞數(shù)據(jù)intent.putExtra("value", "調(diào)用成功");

startActivityForResult(intent,1);//1為請(qǐng)求碼

要想接收Activity返回的值,需要覆蓋onActivityResult事件方法,代碼如下:

@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode, Intent data)

{

Toast.makeText(this, "返回值:" + data.getExtras().getString("result"),

Toast.LENGTH_LONG).show();

}

當(dāng)單擊InvokeActivity中的相應(yīng)按鈕后藏研,并且Main關(guān)閉后业踏,會(huì)顯示如圖4所示的Toast信息提示框伐脖。

從本節(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ù)庫(kù)來存儲(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ù)留夜,也為了簡(jiǎn)化程序代碼,一般將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

本例利用了《基于androidSDK1.5的英文電子詞典的實(shí)現(xiàn)》一文中實(shí)現(xiàn)的電子詞典程序绊困。通過ContentProvider文搂,將電子詞典的查詞功能共享成Cursor對(duì)象。這樣 其他的應(yīng)用程序就可以通過ContentProvider來查詞英文單詞了秤朗。關(guān)于英文詞典的具體實(shí)現(xiàn)細(xì)節(jié)煤蹭,讀者可以通過如下的地址查看《基于androidSDK1.5的英文電子詞典的實(shí)現(xiàn)》一文。

http://www.ophonesdn.com/article/show/111

在電子詞典程序中需要一個(gè)DictionaryContentProvider類取视,該類是ContentProvider的子類硝皂。在該類中實(shí)現(xiàn)了 query方法,并根據(jù)不同的URI來返回不同的結(jié)果作谭。讓我們先看一下DictionaryContentProvider類稽物,然后再對(duì)這些代碼做一些解 釋。

... ...publicclassDictionaryContentProviderextendsContentProvider

{privatestaticUriMatcher uriMatcher;privatestaticfinalString AUTHORITY = "net.blogjava.mobile.dictionarycontentprovider";privatestaticfinalintSINGLE_WORD = 1;privatestaticfinalintPREFIX_WORDS = 2;publicstaticfinalString DATABASE_PATH =android.os.Environment

.getExternalStorageDirectory().getAbsolutePath()+ "/dictionary";publicstaticfinalString DATABASE_FILENAME = "dictionary.db";privateSQLiteDatabase database;static{//添加訪問ContentProvider的UriuriMatcher =newUriMatcher(UriMatcher.NO_MATCH);

uriMatcher.addURI(AUTHORITY,"single", SINGLE_WORD);

uriMatcher.addURI(AUTHORITY,"prefix/*", PREFIX_WORDS);

}//該方法在Activity的onCreate方法之前調(diào)用@OverridepublicbooleanonCreate()

{

database=openDatabase();returntrue;

}//在本例中只實(shí)現(xiàn)了query方法折欠,其他的方法(insert贝或、update和delete)與query方法的實(shí)現(xiàn)//類似@OverridepublicCursor query(Uri uri, String[] projection, String selection,

String[] selectionArgs, String sortOrder)

{

Cursor cursor=null;switch(uriMatcher.match(uri))

{caseSINGLE_WORD://查找指定的單詞cursor = database.query("t_words", projection, selection,

selectionArgs,null,null, sortOrder);break;casePREFIX_WORDS:

String word= uri.getPathSegments().get(1);//查找以指定字符串開頭的單詞集合cursor =database

.rawQuery("select english as _id, chinese from t_words where english like ?",newString[]

{ word+ "%"});break;default:thrownewIllegalArgumentException("<" + uri + ">格式不正確.");

}returncursor;

}

... ...

}

關(guān)于DictionaryContentProvider類的代碼需要做如下的解釋。

1.? 在DictionaryContentProvider類的開頭定義的AUTHORITY是訪問ContentProvider的URI的前半部分锐秦。

2.? 訪問ContentProvider的URI的后半部分由uriMatcher.addURI(...)方法指定咪奖。該方法的第1個(gè)參數(shù)就是 AUTHORITY(Uri的前半部分),第2個(gè)參數(shù)是Uri的后半部分酱床,第3個(gè)參數(shù)是與第2個(gè)參數(shù)值對(duì)應(yīng)的代碼羊赵。當(dāng)其他的應(yīng)用程序通過Uri訪問 ContentProvider時(shí)。系統(tǒng)解析Uri后扇谣,將addURI方法的第2個(gè)參數(shù)值轉(zhuǎn)換成與之對(duì)應(yīng)的代碼(第3個(gè)參數(shù)值)昧捷。

3.? addURI的第2個(gè)參數(shù)值可以使用通配符。例如罐寨,prefix/*中的*表示所有字符靡挥。prefix/abc、prefix/xxx都會(huì)匹配成功衩茸。

4.? 訪問ContentProvider的URI是addURI的第1個(gè)和第2個(gè)參數(shù)值的組件芹血,例如,按著DictionaryContentProvider中設(shè)置的兩個(gè)URI楞慈,可以分別匹配下面的兩個(gè)URI幔烛。

content://net.blogjava.mobile.dictionarycontentprovider/singlecontent://net.blogjava.mobile.dictionarycontentprovider/prefix/wo

要注意的是,訪問ContentProvider的URI必須以“content://”開頭囊蓝。

5.? 在query方法中建議使用SQLiteDatabase對(duì)象的query方法查詢饿悬。因?yàn)閝uery方法的參數(shù)正好和DictionaryContentProvider類中的query方法的參數(shù)對(duì)應(yīng),這樣使用起來比較方便聚霜。

6.? 由于安裝了ContentProvider的應(yīng)用程序會(huì)先調(diào)用ContentProvider的onCreate方法(該方法會(huì)在Activity的 onCreate方法之前調(diào)用)狡恬,因此珠叔,只需要將打開或復(fù)制數(shù)據(jù)庫(kù)的方法(openDatabase)放在 DictionaryContentProvider類中,并在onCreate方法中調(diào)用即可弟劲。

7.? 在DictionaryContentProvider類中只實(shí)現(xiàn)了query方法祷安。在該方法中判斷了其他應(yīng)用程序發(fā)送的是哪一個(gè)Uri。并進(jìn)行相應(yīng)的處理兔乞。這兩個(gè)Uri一個(gè)是查詢指定單詞的汇鞭,另外一個(gè)是查詢以某個(gè)字符串開頭的所有單詞的(用于顯示單詞列表)。

下面在AndroidManifest.xml文件中配置DictionaryContentProvider類庸追。

OK霍骄,現(xiàn)在來看看應(yīng)用程序如何調(diào)用ContentProvider。調(diào)用ContentProvider的關(guān)鍵是使用 getContentResolver方法來獲得一個(gè)ContentResolver對(duì)象淡溯,并通過ContentResolver對(duì)象的query方法來 訪問ContentProvider读整。

首先來定義兩個(gè)訪問ContentProvider的常量。

publicfinalString DICTIONARY_SINGLE_WORD_URI = "content://net.blogjava.mobile.dictionarycontentprovider/single";publicfinalString DICTIONARY_PREFIX_WORD_URI = "content://net.blogjava.mobile.dictionarycontentprovider/prefix";

然后在查詢按鈕的單擊事件中編寫如下的代碼來查詢單詞咱娶。

publicvoidonClick(View view)

{

Uri uri=Uri.parse(DICTIONARY_SINGLE_WORD_URI);//通過ContentProvider查詢單詞米间,并返回Cursor對(duì)象,然后的操作就和直接從數(shù)據(jù)中獲得//Cursor對(duì)象后的操作是一樣的了Cursor cursor = getContentResolver().query(uri,null, "english=?",newString[]{ actvWord.getText().toString() },null);

String result= "未找到該單詞.";if(cursor.getCount() > 0)

{

cursor.moveToFirst();

result= cursor.getString(cursor.getColumnIndex("chinese"));

}newAlertDialog.Builder(this).setTitle("查詢結(jié)果").setMessage(result)

.setPositiveButton("關(guān)閉",null).show();

}

下面是顯示單詞列表的代碼豺总。

publicvoidafterTextChanged(Editable s)

{if("".equals(s.toString()))return;

Uri uri= Uri.parse(DICTIONARY_PREFIX_WORD_URI + "/" +s.toString());//從ContentProvider中獲得以某個(gè)字符串開頭的所有單詞的Cursor對(duì)象Cursor cursor = getContentResolver().query(uri,null,null,null,null);

DictionaryAdapter dictionaryAdapter=newDictionaryAdapter(this,

cursor,true);

actvWord.setAdapter(dictionaryAdapter);

}

現(xiàn)在來運(yùn)行本例车伞,會(huì)看到如圖6所示的界面择懂。當(dāng)查詢單詞時(shí)會(huì)顯示如圖7所示的單詞列表喻喳,查詢出結(jié)果后,會(huì)顯示如圖8所示的界面困曙。

方式三:廣播(Broadcast)

廣播是一種被動(dòng)跨進(jìn)程通訊的方式表伦。當(dāng)某個(gè)程序向系統(tǒng)發(fā)送廣播時(shí),其他的應(yīng)用程序只能被動(dòng)地接收廣播數(shù)據(jù)慷丽。這就象電臺(tái)進(jìn)行廣播一樣蹦哼,聽眾只能被動(dòng)地收聽,而不能主動(dòng)與電臺(tái)進(jìn)行溝通要糊。

在應(yīng)用程序中發(fā)送廣播比較簡(jiǎn)單纲熏。只需要調(diào)用sendBroadcast方法即可。該方法需要一個(gè)Intent對(duì)象锄俄。通過Intent對(duì)象可以發(fā)送需要廣播的數(shù)據(jù)局劲。

先建一個(gè)android工程:sendbroadcast。在XML布局文件中放兩個(gè)組件:EditText和Button奶赠,當(dāng)單擊按鈕后鱼填,會(huì)彈出顯示 EditText組件中文本的對(duì)話框,關(guān)閉對(duì)話框后毅戈, 會(huì)使用sendBroadcast方法發(fā)送消息苹丸,并將EditText組件的文本通過Intent對(duì)象發(fā)送出去愤惰。完整的代碼如下:

packagenet.blogjava.mobile.sendbroadcast;

... ...publicclassMainextendsActivityimplementsOnClickListener

{privateEditText editText;

@OverridepublicvoidonClick(View view)

{newAlertDialog.Builder(this).setMessage(editText.getText().toString())

.setPositiveButton("確定",null).show();//通過Intent類的構(gòu)造方法指定廣播的IDIntent intent =newIntent("net.blogjava.mobile.MYBROADCAST");//將要廣播的數(shù)據(jù)添加到Intent對(duì)象中intent.putExtra("text", editText.getText().toString());//發(fā)送廣播sendBroadcast(intent);

}

... ...

}

發(fā)送廣播并不需要在AndroidManifest.xml文件中注冊(cè),但接收廣播必須在AndroidManifest.xml文件中注冊(cè) receiver赘理。下面來編寫一個(gè)接收廣播的應(yīng)用程序宦言。首先建立一個(gè)android工程:receiver。然后編寫一個(gè)MyReceiver類商模,該類是 BroadcastReceiver的子類蜡励,代碼如下:

packagenet.blogjava.mobile.receiver;

... ...publicclassMyReceiverextendsBroadcastReceiver

{//當(dāng)sendbroadcast發(fā)送廣播時(shí),系統(tǒng)會(huì)調(diào)用onReceive方法來接收廣播@OverridepublicvoidonReceive(Context context, Intent intent)

{//判斷是否為sendbroadcast發(fā)送的廣播if("net.blogjava.mobile.MYBROADCAST".equals(intent.getAction()))

{

Bundle bundle=intent.getExtras();if(bundle !=null)

{

String text= bundle.getString("text");

Toast.makeText(context,"成功接收廣播:" +text, Toast.LENGTH_LONG).show();

}

}

}

}

當(dāng)應(yīng)用程序發(fā)送廣播時(shí)阻桅,系統(tǒng)會(huì)調(diào)用onReceive方法來接收廣播凉倚,并通過intent.getAction()方法返回廣播的ID,也就是在發(fā)送廣播時(shí)Intent構(gòu)造方法指定的字符串嫂沉。然后就可以從Bundle對(duì)象中獲得相應(yīng)的數(shù)據(jù)了稽寒。

最后還需要在AndroidManifest.xml文件中注冊(cè)receiver,代碼如下:

? ? ? ? ? ? ? ? -->

在注冊(cè)MyReceiver類時(shí)需要使用標(biāo)簽,android:name屬性指定MyReceiver類,標(biāo)簽的android:name指定了廣播的ID须揣。

首先運(yùn)行receiver程序杭攻,然后就可以關(guān)閉receiver程序了。接收廣播并不依賴于程序的狀態(tài)孤页。就算程序關(guān)閉了,仍然可以接收廣播。然后再啟動(dòng) sendbroadcast程序谅河。并在文本框中輸入“android”,然后單擊按鈕确丢,會(huì)彈出一個(gè)顯示文本框內(nèi)容的對(duì)話框绷耍,如圖9所示。當(dāng)關(guān)閉對(duì)話框后鲜侥,會(huì) 顯示一個(gè)Toast信息提示框褂始,這個(gè)信息框是由receiver程序彈出的。如圖10所示描函。

方式四:AIDL服務(wù)

服務(wù)(Service)是android系統(tǒng)中非常重要的組件崎苗。Service可以脫離應(yīng)用程序運(yùn)行。也就是說舀寓,應(yīng)用程序只起到一個(gè)啟動(dòng)Service的作用胆数。一但Service被啟動(dòng),就算應(yīng)用程序關(guān)閉基公,Service仍然會(huì)在后臺(tái)運(yùn)行幅慌。

android系統(tǒng)中的Service主要有兩個(gè)作用:后臺(tái)運(yùn)行和跨進(jìn)程通訊。后臺(tái)運(yùn)行就不用說了轰豆,當(dāng)Service啟動(dòng)后胰伍,就可以在Service對(duì)象中 運(yùn)行相應(yīng)的業(yè)務(wù)代碼齿诞,而這一切用戶并不會(huì)察覺。而跨進(jìn)程通訊是這一節(jié)的主題骂租。如果想讓應(yīng)用程序可以跨進(jìn)程通訊祷杈,就要使用我們這節(jié)講的AIDL服 務(wù),AIDL的全稱是Android Interface Definition Language渗饮,也就是說但汞,AIDL實(shí)際上是一種接口定義語言。通過這種語言定義接口后互站,Eclipse插件(ODT)會(huì)自動(dòng)生成相應(yīng)的Java代碼接 口代碼私蕾。下面來看一下編寫一個(gè)AIDL服務(wù)的基本步驟。

1.? 在Eclipse工程的package目錄中建立一個(gè)擴(kuò)展名為aidl的文件胡桃。package目錄就是Java類所在的目錄踩叭。該文件的語法類似于Java代碼。aidl文件中定義的是AIDL服務(wù)的接口翠胰。這個(gè)接口需要在調(diào)用AIDL服務(wù)的程序中訪問容贝。

2.? 如果aidl文件的內(nèi)容是正確的,Eclipse插件會(huì)自動(dòng)生成一個(gè)Java接口文件(*.java)之景。

3.? 建立一個(gè)服務(wù)類(Service的子類)斤富。

4.? 實(shí)現(xiàn)由aidl文件生成的Java接口。

5.? 在AndroidManifest.xml文件中配置AIDL服務(wù)锻狗,尤其要注意的是满力,標(biāo)簽的android:name屬性值就是客戶端要引用該服務(wù)的ID,也就是Intent類構(gòu)造方法的參數(shù)值屋谭。

現(xiàn)在我們來編寫一個(gè)AIDL服務(wù)脚囊,首先建立一個(gè)android工程:aidlservice龟糕。在aidlservice工程中有一個(gè)Main類桐磁,在Main類所有的目錄建立一個(gè)IMyService.aidl文件,內(nèi)容如下:

packagenet.blogjava.mobile.aidlservice;interfaceIMyService

{

String getValue();//為AIDL服務(wù)的接口方法讲岁,調(diào)用AIDL服務(wù)的程序需要調(diào)用該方法}

在保存IMyService.aidl文件后我擂,ODT會(huì)在gen目錄下產(chǎn)生一個(gè)IMyService.java文件,讀者可以不必管這個(gè)文件中的內(nèi)容缓艳,也 不需要修改該文件的內(nèi)容校摩。這個(gè)文件是由ODT自動(dòng)維護(hù)的,只要修改了IMyService.aidl文件的內(nèi)容阶淘,IMyService.java文件的內(nèi) 容就會(huì)隨之改變衙吩。

然后建立一個(gè)MyService類,該類是Service的子類溪窒,代碼如下:

packagenet.blogjava.mobile.aidlservice;

... ...publicclassMyServiceextendsService

{//IMyService.Stub類是根據(jù)IMyService.aidl文件生成的類坤塞,該類中包含了接口方法(getValue)publicclassMyServiceImplextendsIMyService.Stub

{

@OverridepublicString getValue()throwsRemoteException

{return"從AIDL服務(wù)獲得的值.";

}

}

@OverridepublicIBinder onBind(Intent intent)

{//該方法必須返回MyServiceImpl類的對(duì)象實(shí)例returnnewMyServiceImpl();

}

}

最后需要在AndroidManifest.xml文件中配置MyService類冯勉,代碼如下:

下面來看看如何調(diào)用這個(gè)AIDL服務(wù)。首先建立一個(gè)android工程:aidlclient摹芙。然后將aidlservice工程中自動(dòng)生成的 IMyService.java文件復(fù)制到aidlclient工程中灼狰。在調(diào)用AIDL服務(wù)之前需要先使用bindService方法綁定AIDL服務(wù)。 bindService方法需要一個(gè)ServiceConnection對(duì)象浮禾。ServiceConnection有一個(gè) onServiceConnected方法交胚,當(dāng)成功綁定AIDL服務(wù)且,該方法被調(diào)用盈电。并通過service參數(shù)返回AIDL服務(wù)對(duì)象蝴簇。下面是調(diào)用 AIDL服務(wù)的完成代碼。

packagenet.blogjava.mobile.aidlclient;

... ...publicclassMainextendsActivityimplementsOnClickListener

{privateIMyService myService =null;//創(chuàng)建ServiceConnection對(duì)象privateServiceConnection serviceConnection =newServiceConnection()

{

@OverridepublicvoidonServiceConnected(ComponentName name, IBinder service)

{//獲得AIDL服務(wù)對(duì)象myService =IMyService.Stub.asInterface(service);try{//調(diào)用AIDL服務(wù)對(duì)象中的getValue方法匆帚,并以對(duì)話框中顯示該方法的返回值newAlertDialog.Builder(Main.this).setMessage(

myService.getValue()).setPositiveButton("確定",null)

.show();

}catch(Exception e)

{

}

}

@OverridepublicvoidonServiceDisconnected(ComponentName name)

{

}

};

@OverridepublicvoidonClick(View view)

{//綁定AIDL服務(wù)bindService(newIntent("net.blogjava.mobile.aidlservice.IMyService"),

serviceConnection, Context.BIND_AUTO_CREATE);

}

... ...

}

在編寫AIDL服務(wù)和客戶端時(shí)要注意如下兩點(diǎn):

1.? AIDL服務(wù)中的onBind方法必須返回AIDL接口對(duì)象(MyServiceImpl對(duì)象)军熏。該對(duì)象也是onServiceConnected事件方法的第2個(gè)參數(shù)值。

2.? bindService方法的第1個(gè)參數(shù)是Intent對(duì)象卷扮,該對(duì)象構(gòu)造方法的參數(shù)需要指定AIDL服務(wù)的ID荡澎,也就是在 AndroidManifest.xml文件中標(biāo)簽的子標(biāo)簽的android:name屬性 的值。

現(xiàn)在先運(yùn)行aidlservice程序晤锹,以便安裝AIDL服務(wù)摩幔,然后運(yùn)行aidlclient程序,并單擊按鈕鞭铆,會(huì)顯示如圖11所示的對(duì)話框或衡。對(duì)話框中的信息就是AIDL服務(wù)接口中g(shù)etValue方法的返回值。

總結(jié)

本文介紹了4種跨進(jìn)程通訊的方式:Activity车遂、ContentProvider封断、Broadcast和AIDL Service。其中Activity可以跨進(jìn)程調(diào)用其他應(yīng)用程序的Activity舶担;ContentProvider可以訪問其他應(yīng)用程序返回的 Cursor對(duì)象坡疼;Broadcast采用的是被動(dòng)接收的方法,也就是說衣陶,客戶端只能接收廣播數(shù)據(jù)柄瑰,而不能向發(fā)送廣播的程序發(fā)送信息。AIDL Service可以將程序中的某個(gè)接口公開剪况,這樣在其他的應(yīng)用程序中就可以象訪問本地對(duì)象一樣訪問AIDL服務(wù)對(duì)象了教沾。這4種跨進(jìn)程通訊的方式可以應(yīng)用在 不同的場(chǎng)合,例如译断,在需要顯示可視化的界面時(shí)可以用Activity授翻,需要返回記錄集時(shí)可以用ContentProvider。至于在應(yīng)用程序中具體要用 到哪一種或幾種方式進(jìn)行跨進(jìn)程通訊,讀者可以根據(jù)實(shí)際情況進(jìn)行選擇堪唐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隆箩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子羔杨,更是在濱河造成了極大的恐慌捌臊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兜材,死亡現(xiàn)場(chǎng)離奇詭異理澎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)曙寡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門糠爬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人举庶,你說我怎么就攤上這事执隧。” “怎么了户侥?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵镀琉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我蕊唐,道長(zhǎng)屋摔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任替梨,我火速辦了婚禮钓试,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘副瀑。我一直安慰自己弓熏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布糠睡。 她就那樣靜靜地躺著挽鞠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铜幽。 梳的紋絲不亂的頭發(fā)上滞谢,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音除抛,去河邊找鬼。 笑死母截,一個(gè)胖子當(dāng)著我的面吹牛到忽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼喘漏,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼护蝶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起翩迈,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤持灰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后负饲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堤魁,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年返十,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妥泉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洞坑,死狀恐怖盲链,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迟杂,我是刑警寧澤刽沾,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站排拷,受9級(jí)特大地震影響悠轩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜攻泼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一火架、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忙菠,春花似錦何鸡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至傍睹,卻和暖如春隔盛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拾稳。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工吮炕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人访得。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓龙亲,卻偏偏與公主長(zhǎng)得像陕凹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鳄炉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 由于android系統(tǒng)中應(yīng)用程序之間不能共享內(nèi)存杜耙。 因此,在不同應(yīng)用程序之間交互數(shù)據(jù)(跨進(jìn)程通訊)就稍微麻煩一些拂盯。...
    IT楓閱讀 6,726評(píng)論 0 5
  • 1佑女、Androiddvm的進(jìn)程和Linux的進(jìn)程, 應(yīng)用程序的進(jìn)程是否為同一個(gè)概念 DVM指dalivk的虛擬機(jī)。...
    ifeng_max閱讀 933評(píng)論 0 10
  • 哎呀呀 ,馬上就要面臨找工作了,媛媛心里緊張呀. 作為一個(gè)即將畢業(yè)的Android程序媛,開始面臨找工作了,...
    左神話閱讀 4,556評(píng)論 7 59
  • 甚至懷疑濾鏡色調(diào)的靈感都源自這里 完全不需要后期 簡(jiǎn)單的原圖拼湊已經(jīng)美的一塌糊涂 拉市海的藍(lán) 夢(mèng)幻 甚至虛假 難以...
    胖T閱讀 276評(píng)論 0 4
  • 今天我讀了《大象的女兒》里面的好詞好句有:小心翼翼谈竿,無比擔(dān)憂团驱,霧氣籠罩著整個(gè)森林,仿佛一種仙樂一般漂浮在大家的心頭...
    邵昱晗閱讀 680評(píng)論 0 0