<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 93,  comments - 2,  trackbacks - 0

    android中跨進程通訊的4種方式

    轉自:http://www.cnblogs.com/sevenyuan/archive/2013/03/22/2975122.html

    由于android系統中應用程序之間不能共享內存。因此,在不同應用程序之間交互數據(跨進程通訊)就稍微麻煩一些。在android SDK中提供了4種用于跨進程通訊的方式。這4種方式正好對應于android系統中4種應用程序組件:Activity、Content Provider、Broadcast和Service。

      其中Activity可以跨進程調用其他應用程序的Activity;
      Content Provider可以跨進程訪問其他應用程序中的數據(以Cursor對象形式返回),當然,也可以對其他應用程序的數據進行增、刪、改操 作;
      Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播;
      Service和Content Provider類似,也可以訪問其他應用程序中的數據,但不同的是,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫AIDL服務。

    完整示例請參閱本文提供的源代碼。

    方式一:訪問其他應用程序的Activity
    Activity既可以在進程內(同一個應用程序)訪問,也可以跨進程訪問。如果想在同一個應用程序中訪問Activity,需要指定Context對象和Activity的Class對象,代碼如下:

    Intent intent = new  Intent(this , Test.class );  
    startActivity(intent);  

    Activity的跨進程訪問與進程內訪問略有不同。雖然它們都需要Intent對象,但跨進程訪問并不需要指定Context對象和Activity的 Class對象,而需要指定的是要訪問的Activity所對應的Action(一個字符串)。有些Activity還需要指定一個Uri(通過 Intent構造方法的第2個參數指定)。

    在android系統中有很多應用程序提供了可以跨進程訪問的Activity,例如,下面的代碼可以直接調用撥打電話的Activity。

    Intent callIntent = new  Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678" );  
    startActivity(callIntent);  

    執行上面的代碼后,系統會自動撥號,界面如圖1所示。

     

    在調用撥號程序的代碼中使用了一個Intent.ACTION_CALL常量,該常量的定義如下:

    public  static  final  String ACTION_CALL = "android.intent.action.CALL" ;  

            這個常量是一個字符串常量,也是我們在這節要介紹的跨進程調用Activity的關鍵。如果在應用程序中要共享某個Activity,需要為這個 Activity指定一個字符串ID,也就是Action。也可以將這個Action看做這個Activity的key。在其他的應用程序中只要通過這個 Action就可以找到與Action對應的Activity,并通過startActivity方法來啟動這個Activity。

            下面先來看一下如何將應用程序的Activity共享出來,讀者可按如下幾步來共享Activity:
    1.  在AndroidManifest.xml文件中指定Action。指定Action要使用<action>標簽,并在該標簽的android:name屬性中指定Action
    2.  在AndroidManifest.xml文件中指定訪問協議。在指定Uri(Intent類的第2個參數)時需要訪問協議。訪問協議需要使 用<data>標簽的android:scheme屬性來指定。如果該屬性的值是“abc”,那么Uri就應該是“abc://Uri的主體 部分”,也就是說,訪問協議是Uri的開頭部分。
    3.  通過getIntent().getData().getHost()方法獲得協議后的Uri的主體部分。這個Host只是個稱謂,并不一定是主機名。讀者可以將其看成是任意的字符串。
    4.  從Bundle對象中獲得其他應用程序傳遞過來的數據。
    5.  這一步當然是獲得數據后做進一步的處理了。至于如何處理這些數據,就得根據具體的需求決定了。

            下面來根據這些步驟共享一個Activity。首先建立一個android工程(ActionActivity),工程的主Activity是Main。在 本例中我們會共享這個Main類。首先打開AndroidManifest.xml文件,添加一個<activity>標簽,并重新定義了 Main的相應屬性。AndroidManifest.xml文件的內容如下:

    復制代碼
    <!--  重新配置Main  -->
    <activity android:name=".Main" android:label="@string/app_name">
        <intent-filter>    
            <action android:name="net.blogjava.mobile.MYACTION" />
            <data android:scheme="info" />            
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
    復制代碼

          在配置AndroidManifest.xml時要注意,不能在同一個<activity>中配置多個動作,否則會覆蓋MAIN動作以使該程序無法正常啟動(雖然其他應用程序調用Main是正常的)。

          從上面的代碼可以看出,<action>標簽的android:name屬性值是 net.blogjava.mobile.MYACTION,這就是Main自定義的動作。<data>標簽指定了Url的協議。如果指定 了<data>標簽的android:scheme屬性值(info),則在調用Main時需要使用如下的URL:

    info://任意字符串   

             一般<category>標簽的android:name屬性值可以設成android.intent.category.DEFAULT。

             下面來看看如何在Main類的onCreate方法中獲得其他應用程序傳遞過來的數據。

    復制代碼
    package net.blogjava.mobile.actionactivity;
    ... ...
    public class Main extends Activity implements OnClickListener
    {
        private EditText editText;
        @Override
        public void onClick(View view)
        {
            //  單擊按鈕,會顯示文本框中的內容(以Toast信息框形式顯示)
            Toast.makeText(this, editText.getText().toString(), Toast.LENGTH_LONG)
                    .show();
        }
        @Override
        public void onCreate(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);
            //  獲得其他應用程序傳遞過來的數據
            if (getIntent().getData() != null)
            {
                //  獲得Host,也就是info://后面的內容
                String host = getIntent().getData().getHost();
                Bundle bundle = getIntent().getExtras();
                //  其他的應用程序會傳遞過來一個value值,在該應用程序中需要獲得這個值
                String value = bundle.getString("value");
                //  將Host和Value組合在一下顯示在EditText組件中
                editText.setText(host + ":" + value);
                //  調用了按鈕的單擊事件,顯示Toast信息提示框
                onClick(button);
            }
        }
    }
    復制代碼

           從上面的程序可以看出,首先通過getIntent().getData()來判斷其他的應用程序是否傳遞了Uri(getData方法返回了一個Uri 對象)。如果運行該程序,Uri為null,因此,不會執行if語句里面的代碼。當其他的應用程序傳遞了Uri對象后,系統會執行if語句里面的代碼。當 運行ActionActivity后,在文本框中輸入“Running”,單擊“顯示文本框的內容”按鈕,會顯示如圖2所示的Toast提示信息框。

     

          下面來看一下其他的應用程序是如何調用ActionActivity中的Main。新建一個android工程(InvokeActivity),并添加一個按鈕,按鈕的單擊事件方法代碼如下:

    復制代碼
    public void onClick(View view)
    {
        //  需要使用Intent類的第2個參數指定Uri
        Intent intent = new Intent("net.blogjava.mobile.MYACTION", Uri
                .parse("info://調用其他應用程序的Activity"));
        //  設置value屬性值
        intent.putExtra("value", "調用成功");
        //  調用ActionActivity中的Main
        startActivity(intent);
    }
    復制代碼

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

     

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

    復制代碼
    public void onClick(View view)
    {
        Toast.makeText(this, editText.getText().toString(), Toast.LENGTH_LONG).show();
        Intent intent = new Intent();
        //  設置要返回的屬性值
        intent.putExtra("result", editText.getText().toString());
        //  設置返回碼和Intent對象
        setResult(2, intent);
        //  關閉Activity
        finish();
    }
    復制代碼

     然后在InvokeActivity中使用下面的代碼來調用Main。

    intent = new Intent("net.blogjava.mobile.MYACTION", Uri
            .parse("info://調用其他應用程序的Activity"));
    //  傳遞數據
    intent.putExtra("value", "調用成功");
    startActivityForResult(intent, 1);                //  1為請求碼

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

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        Toast.makeText(this, "返回值:" + data.getExtras().getString("result"),
                Toast.LENGTH_LONG).show();
    }

     當單擊InvokeActivity中的相應按鈕后,并且Main關閉后,會顯示如圖4所示的Toast信息提示框。

     

    從本節的介紹可以看出,跨進程訪問Activity(訪問其他應用程序中的Activity)主要是通過一個Action來完成的,如果要傳遞數據,還需 要指定一個Uri。當然,傳遞數據也可以通過Intent來完成。傳遞數據的過程可以是雙向的。如果要想從調用的Activity中返回數據,就需要使用 startActivityForResult方法來啟動Activity了。

    方式二:Content Provider 
          Android應用程序可以使用文件或SqlLite數據庫來存儲數據。Content Provider提供了一種在多個應用程序之間數據共享的方式(跨進程共享數據)。應用程序可以利用Content Provider完成下面的工作

    1. 查詢數據
    2. 修改數據
    3. 添加數據
    4. 刪除數據

            雖然Content Provider也可以在同一個應用程序中被訪問,但這么做并沒有什么意義。Content Provider存在的目的向其他應用程序共享數據和允許其他應用程序對數據進行增、刪、改操作。
    Android系統本身提供了很多Content Provider,例如,音頻、視頻、聯系人信息等等。我們可以通過這些Content Provider獲得相關信息的列表。這些列表數據將以Cursor對象返回。因此,從Content Provider返回的數據是二維表的形式。

          對于訪問Content Provider的程序,需要使用ContentResolver對象。該對象需要使用getContentResolver方法獲得,代碼如下:

    ContentResolver cr = getContentResolver();

     與Activity一樣,Content Provider也需要與一個URI對應。每一個Content Provider可以控制多個數據集,在這種情況下,每一個數據集會對應一個單獨的URI。所有的URI必須以“content://”開頭。
    為了程序更容易維護,也為了簡化程序代碼,一般將URI定義成一個常量。例如,下面的常量表示系統的聯系人電話號碼。

    android.provider.Contacts.Phones.CONTENT_URI 

    下面來看一下編寫Content Provider的具體步驟。

    1.  編寫一個繼承于android.content.ContentProvider的子類。該類是ContentProvider的核心類。在該類中會實現 query、insert、update及delete方法。實際上調用ContentResolver類的這4個方法就是調用 ContentProvider類中與之要對應的方法。在本文中只介紹query。至于insert、update、delete和query的用法類 似。也是通過Uri傳遞參數,然后在這些方法中接收這些參數,并做進一步地處理。
    2.  在AndroidManifest.xml文件中配置ContentProvider。要想唯一確定一個ContentProvider,需要指定這個 ContentProvider的URI,除此之外,還需要指定URI所對應的ContentProvider類。這有些象Servlet的定義,除了要 指定Servlet對應的Web地址,還要指定這個地址所對應的Servlet類。
    現在來看一下Uri的具體格式,先看一下如圖5所示的URI。

    下面對圖5所示的URI的4個部分做一下解釋。

    A:Content Provider URI的固定前綴,也就是說,所有的URI必須以content://開頭。
    B:URI中最重要的部分。該部分是Content Provider的唯一標識。對于第三方應用程序來說,該部分最后使用完整的類名(包名+類名),以確保URI的唯一性。該部分需要在 AndroidManifest.xml文件中<provider>標簽中定義,代碼如下:

    <provider name=".TransportationProvider" authorities="com.example.transportationprovider"
              . . .  >

    C:這部分是URI的路徑(path)。表示URI中各種被請求的數據。這部分是可選的, 如果Content Provider僅僅提供一種請求的數據,那么這部分可以省略。如果Content Provider要提供多種請求數據。就需要添加多個路徑,甚至是子路徑。例如,“land/bus”、“land/train”、“sea/ship” 就指定了3種可能提供的數據。
    D:這部分也是可選的。如果要傳遞一個值給Content Provider,可以通過這部分傳遞。當然,如果不需要傳值,這部分也可以省略,省略后的URI如下所示:

    content://com.example.transportationprovider/trains

     本例利用了《基于 android SDK1.5的英文電子詞典的實現》一文中實現的電子詞典程序。通過ContentProvider,將電子詞典的查詞功能共享成Cursor對象。這樣 其他的應用程序就可以通過ContentProvider來查詞英文單詞了。關于英文詞典的具體實現細節,讀者可以通過如下的地址查看《基于android SDK1.5的英文電子詞典的實現》一文。

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

    在電子詞典程序中需要一個DictionaryContentProvider類,該類是ContentProvider的子類。在該類中實現了 query方法,并根據不同的URI來返回不同的結果。讓我們先看一下DictionaryContentProvider類,然后再對這些代碼做一些解 釋。

    復制代碼
    ... ...
    public class DictionaryContentProvider extends ContentProvider
    {
        private static UriMatcher uriMatcher;
        private static final String AUTHORITY = "net.blogjava.mobile.dictionarycontentprovider";
        private static final int SINGLE_WORD = 1;
        private static final int PREFIX_WORDS = 2;
        public static final String DATABASE_PATH = android.os.Environment
        .getExternalStorageDirectory().getAbsolutePath()
        + "/dictionary";
        public static final String DATABASE_FILENAME = "dictionary.db";
        private SQLiteDatabase database;
        static
        {
            //  添加訪問ContentProvider的Uri
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            uriMatcher.addURI(AUTHORITY, "single", SINGLE_WORD);
            uriMatcher.addURI(AUTHORITY, "prefix/*", PREFIX_WORDS);
        }
        //  該方法在Activity的onCreate方法之前調用
        @Override
        public boolean onCreate()
        {
            database = openDatabase();
            return true;
        }
        //  在本例中只實現了query方法,其他的方法(insert、update和delete)與query方法的實現
        //  類似
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder)
        {
            Cursor cursor = null;
            switch (uriMatcher.match(uri))
            {
                case SINGLE_WORD:
                    //  查找指定的單詞
                    cursor = database.query("t_words", projection, selection,
                            selectionArgs, null, null, sortOrder);
                    break;
                case PREFIX_WORDS:
                    String word = uri.getPathSegments().get(1);
                    //  查找以指定字符串開頭的單詞集合
                    cursor = database
                            .rawQuery(
                                    "select english as _id, chinese from t_words where english like ?",
                                    new String[]
                                    { word + "%" });
                    break;
    
                default:
                    throw new IllegalArgumentException("<" + uri + ">格式不正確.");
            }
            return cursor;
        }
        ... ...
    }
    復制代碼

    關于DictionaryContentProvider類的代碼需要做如下的解釋。


    1.  在DictionaryContentProvider類的開頭定義的AUTHORITY是訪問ContentProvider的URI的前半部分。
    2.  訪問ContentProvider的URI的后半部分由uriMatcher.addURI(...)方法指定。該方法的第1個參數就是 AUTHORITY(Uri的前半部分),第2個參數是Uri的后半部分,第3個參數是與第2個參數值對應的代碼。當其他的應用程序通過Uri訪問 ContentProvider時。系統解析Uri后,將addURI方法的第2個參數值轉換成與之對應的代碼(第3個參數值)。
    3.  addURI的第2個參數值可以使用通配符。例如,prefix/*中的*表示所有字符。prefix/abc、prefix/xxx都會匹配成功。
    4.  訪問ContentProvider的URI是addURI的第1個和第2個參數值的組件,例如,按著DictionaryContentProvider中設置的兩個URI,可以分別匹配下面的兩個URI。

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

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


    5.  在query方法中建議使用SQLiteDatabase對象的query方法查詢。因為query方法的參數正好和DictionaryContentProvider類中的query方法的參數對應,這樣使用起來比較方便。
    6.  由于安裝了ContentProvider的應用程序會先調用ContentProvider的onCreate方法(該方法會在Activity的 onCreate方法之前調用),因此,只需要將打開或復制數據庫的方法(openDatabase)放在 DictionaryContentProvider類中,并在onCreate方法中調用即可。
    7.  在DictionaryContentProvider類中只實現了query方法。在該方法中判斷了其他應用程序發送的是哪一個Uri。并進行相應的處理。這兩個Uri一個是查詢指定單詞的,另外一個是查詢以某個字符串開頭的所有單詞的(用于顯示單詞列表)。
    下面在AndroidManifest.xml文件中配置DictionaryContentProvider類。

    <provider android:name="DictionaryContentProvider"
                android:authorities="net.blogjava.mobile.dictionarycontentprovider" />  

     OK,現在來看看應用程序如何調用ContentProvider。調用ContentProvider的關鍵是使用 getContentResolver方法來獲得一個ContentResolver對象,并通過ContentResolver對象的query方法來 訪問ContentProvider。

            首先來定義兩個訪問ContentProvider的常量。

    public final String DICTIONARY_SINGLE_WORD_URI = "content://net.blogjava.mobile.dictionarycontentprovider/single";
    public final String DICTIONARY_PREFIX_WORD_URI = "content://net.blogjava.mobile.dictionarycontentprovider/prefix";

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

    復制代碼
    public void onClick(View view)
    {
        Uri uri = Uri.parse(DICTIONARY_SINGLE_WORD_URI);
        //  通過ContentProvider查詢單詞,并返回Cursor對象,然后的操作就和直接從數據中獲得
        //  Cursor對象后的操作是一樣的了
        Cursor cursor = getContentResolver().query(uri, null, "english=?",
                new String[]{ actvWord.getText().toString() }, null);
        String result = "未找到該單詞.";
        if (cursor.getCount() > 0)
        {
            cursor.moveToFirst();
            result = cursor.getString(cursor.getColumnIndex("chinese"));
        }
        new AlertDialog.Builder(this).setTitle("查詢結果").setMessage(result)
                .setPositiveButton("關閉", null).show();
    
    }
    復制代碼

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

    復制代碼
    public void afterTextChanged(Editable s)
    {
        if ("".equals(s.toString()))
            return;
        Uri uri = Uri.parse(DICTIONARY_PREFIX_WORD_URI + "/" + s.toString());
        //  從ContentProvider中獲得以某個字符串開頭的所有單詞的Cursor對象
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        DictionaryAdapter dictionaryAdapter = new DictionaryAdapter(this,
                cursor, true);
        actvWord.setAdapter(dictionaryAdapter);
    }
    復制代碼

     現在來運行本例,會看到如圖6所示的界面。當查詢單詞時會顯示如圖7所示的單詞列表,查詢出結果后,會顯示如圖8所示的界面。

     

    方式三:廣播(Broadcast) 
          廣播是一種被動跨進程通訊的方式。當某個程序向系統發送廣播時,其他的應用程序只能被動地接收廣播數據。這就象電臺進行廣播一樣,聽眾只能被動地收聽,而不能主動與電臺進行溝通。
    在應用程序中發送廣播比較簡單。只需要調用sendBroadcast方法即可。該方法需要一個Intent對象。通過Intent對象可以發送需要廣播的數據。

         先建一個android工程:sendbroadcast。在XML布局文件中放兩個組件:EditText和Button,當單擊按鈕后,會彈出顯示 EditText組件中文本的對話框,關閉對話框后, 會使用sendBroadcast方法發送消息,并將EditText組件的文本通過Intent對象發送出去。完整的代碼如下:

    復制代碼
    package net.blogjava.mobile.sendbroadcast;
    ... ...
    public class Main extends Activity implements OnClickListener
    {
        private EditText editText;
        @Override
        public void onClick(View view)
        {
            new AlertDialog.Builder(this).setMessage(editText.getText().toString())
                    .setPositiveButton("確定", null).show();     
            //  通過Intent類的構造方法指定廣播的ID
            Intent intent = new Intent("net.blogjava.mobile.MYBROADCAST");
            //  將要廣播的數據添加到Intent對象中  
            intent.putExtra("text", editText.getText().toString());
            //  發送廣播  
            sendBroadcast(intent);
        }
        ... ...
    }
    復制代碼

    發送廣播并不需要在AndroidManifest.xml文件中注冊,但接收廣播必須在AndroidManifest.xml文件中注冊 receiver。下面來編寫一個接收廣播的應用程序。首先建立一個android工程:receiver。然后編寫一個MyReceiver類,該類是 BroadcastReceiver的子類,代碼如下:

    復制代碼
    package net.blogjava.mobile.receiver;
    ... ...
    public class MyReceiver extends BroadcastReceiver
    {
        //  當sendbroadcast發送廣播時,系統會調用onReceive方法來接收廣播
        @Override
        public void onReceive(Context context, Intent intent)
    {
        //  判斷是否為sendbroadcast發送的廣播
            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();
                }
            }
        }
    }
    復制代碼

         當應用程序發送廣播時,系統會調用onReceive方法來接收廣播,并通過intent.getAction()方法返回廣播的ID,也就是在發送廣播時Intent構造方法指定的字符串。然后就可以從Bundle對象中獲得相應的數據了。

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

    復制代碼
    <!--  注冊receiver ?
    <receiver android:name="MyReceiver">
        <intent-filter>
            <action android:name="net.blogjava.mobile.MYBROADCAST" />
        </intent-filter>
    </receiver>
    復制代碼

    在注冊MyReceiver類時需要使用<receiver>標簽,android:name屬性指定MyReceiver類,<action>標簽的android:name指定了廣播的ID。

            首先運行receiver程序,然后就可以關閉receiver程序了。接收廣播并不依賴于程序的狀態。就算程序關閉了,仍然可以接收廣播。然后再啟動 sendbroadcast程序。并在文本框中輸入“android”,然后單擊按鈕,會彈出一個顯示文本框內容的對話框,如圖9所示。當關閉對話框后,會 顯示一個Toast信息提示框,這個信息框是由receiver程序彈出的。如圖10所示。

    方式四:AIDL服務
           服務(Service)是android系統中非常重要的組件。Service可以脫離應用程序運行。也就是說,應用程序只起到一個啟動Service的作用。一但Service被啟動,就算應用程序關閉,Service仍然會在后臺運行。

           android系統中的Service主要有兩個作用:后臺運行和跨進程通訊。后臺運行就不用說了,當Service啟動后,就可以在Service對象中 運行相應的業務代碼,而這一切用戶并不會察覺。而跨進程通訊是這一節的主題。如果想讓應用程序可以跨進程通訊,就要使用我們這節講的AIDL服 務,AIDL的全稱是Android Interface Definition Language,也就是說,AIDL實際上是一種接口定義語言。通過這種語言定義接口后,Eclipse插件(ODT)會自動生成相應的Java代碼接 口代碼。下面來看一下編寫一個AIDL服務的基本步驟。

    1.  在Eclipse工程的package目錄中建立一個擴展名為aidl的文件。package目錄就是Java類所在的目錄。該文件的語法類似于Java代碼。aidl文件中定義的是AIDL服務的接口。這個接口需要在調用AIDL服務的程序中訪問。
    2.  如果aidl文件的內容是正確的,Eclipse插件會自動生成一個Java接口文件(*.java)。
    3.  建立一個服務類(Service的子類)。
    4.  實現由aidl文件生成的Java接口。
    5.  在AndroidManifest.xml文件中配置AIDL服務,尤其要注意的是,<action>標簽的android:name屬性值就是客戶端要引用該服務的ID,也就是Intent類構造方法的參數值。

          現在我們來編寫一個AIDL服務,首先建立一個android工程:aidlservice。在aidlservice工程中有一個Main類,在Main類所有的目錄建立一個IMyService.aidl文件,內容如下:

    package net.blogjava.mobile.aidlservice;
    interface IMyService
    {
        String getValue();    //  為AIDL服務的接口方法,調用AIDL服務的程序需要調用該方法
    }

    在保存IMyService.aidl文件后,ODT會在gen目錄下產生一個IMyService.java文件,讀者可以不必管這個文件中的內容,也 不需要修改該文件的內容。這個文件是由ODT自動維護的,只要修改了IMyService.aidl文件的內容,IMyService.java文件的內 容就會隨之改變。

            然后建立一個MyService類,該類是Service的子類,代碼如下:

    復制代碼
    package net.blogjava.mobile.aidlservice;
    ... ...
    public class MyService extends Service
    {
        //  IMyService.Stub類是根據IMyService.aidl文件生成的類,該類中包含了接口方法(getValue)
        public class MyServiceImpl extends IMyService.Stub
        {
            @Override
            public String getValue() throws RemoteException
            {
                return "從AIDL服務獲得的值.";
            }
        }
        @Override
        public IBinder onBind(Intent intent)
    {        
    //  該方法必須返回MyServiceImpl類的對象實例
            return new MyServiceImpl();
        }
    }
    復制代碼

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

    復制代碼
    <!--  注冊服務 -->
    <service android:name=".MyService">
        <intent-filter>
            <!--  指定調用AIDL服務的ID  -->
            <action android:name="net.blogjava.mobile.aidlservice.IMyService" />
        </intent-filter>
    </service>
    復制代碼

      下面來看看如何調用這個AIDL服務。首先建立一個android工程:aidlclient。然后將aidlservice工程中自動生成的 IMyService.java文件復制到aidlclient工程中。在調用AIDL服務之前需要先使用bindService方法綁定AIDL服務。 bindService方法需要一個ServiceConnection對象。ServiceConnection有一個 onServiceConnected方法,當成功綁定AIDL服務且,該方法被調用。并通過service參數返回AIDL服務對象。下面是調用 AIDL服務的完成代碼。

    復制代碼
    package net.blogjava.mobile.aidlclient;
    ... ...
    public class Main extends Activity implements OnClickListener
    {
    private IMyService myService = null;
    //  創建ServiceConnection對象
        private ServiceConnection serviceConnection = new ServiceConnection()
        {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service)
            {
                // 獲得AIDL服務對象
                myService = IMyService.Stub.asInterface(service);
                try
                {
                    //  調用AIDL服務對象中的getValue方法,并以對話框中顯示該方法的返回值
                    new AlertDialog.Builder(Main.this).setMessage(
                            myService.getValue()).setPositiveButton("確定", null)
                            .show();
                }
                catch (Exception e)
                {
                }
            }
            @Override
            public void onServiceDisconnected(ComponentName name)
            {
            }
        };
        @Override
        public void onClick(View view)
    {
        //  綁定AIDL服務
            bindService(new Intent("net.blogjava.mobile.aidlservice.IMyService"),
                    serviceConnection, Context.BIND_AUTO_CREATE);
        }
        ... ...
    }
    復制代碼

    在編寫AIDL服務和客戶端時要注意如下兩點:

    1.  AIDL服務中的onBind方法必須返回AIDL接口對象(MyServiceImpl對象)。該對象也是onServiceConnected事件方法的第2個參數值。
    2.  bindService方法的第1個參數是Intent對象,該對象構造方法的參數需要指定AIDL服務的ID,也就是在 AndroidManifest.xml文件中<service>標簽的<action>子標簽的android:name屬性 的值。

     現在先運行aidlservice程序,以便安裝AIDL服務,然后運行aidlclient程序,并單擊按鈕,會顯示如圖11所示的對話框。對話框中的信息就是AIDL服務接口中getValue方法的返回值。

    總結 
          本文介紹了4種跨進程通訊的方式:Activity、ContentProvider、Broadcast和AIDL Service。其中Activity可以跨進程調用其他應用程序的Activity;ContentProvider可以訪問其他應用程序返回的 Cursor對象;Broadcast采用的是被動接收的方法,也就是說,客戶端只能接收廣播數據,而不能向發送廣播的程序發送信息。AIDL Service可以將程序中的某個接口公開,這樣在其他的應用程序中就可以象訪問本地對象一樣訪問AIDL服務對象了。這4種跨進程通訊的方式可以應用在 不同的場合,例如,在需要顯示可視化的界面時可以用Activity,需要返回記錄集時可以用ContentProvider。至于在應用程序中具體要用 到哪一種或幾種方式進行跨進程通訊,讀者可以根據實際情況進行選擇。

    posted on 2015-06-24 17:28 Terry Zou 閱讀(501) 評論(0)  編輯  收藏 所屬分類: Android
    <2015年6月>
    31123456
    78910111213
    14151617181920
    21222324252627
    2829301234
    567891011

    常用鏈接

    留言簿(2)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    相冊

    收藏夾

    Java

    搜索

    •  

    最新隨筆

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 成人嫩草影院免费观看| 久久亚洲AV成人无码软件| 免费在线观看a级毛片| 亚洲人成人无码.www石榴 | 日本免费人成视频在线观看| 成年免费a级毛片免费看无码| 一个人免费观看视频在线中文| 亚洲免费在线视频观看| 在线精品亚洲一区二区小说| 久久久无码精品亚洲日韩软件| 久久精品亚洲福利| 亚洲色自偷自拍另类小说| 亚洲高清专区日韩精品| 久久精品7亚洲午夜a| 亚洲自偷自拍另类12p| 亚洲精品国产V片在线观看| 五月婷婷综合免费| 成人免费视频小说| 成人免费无码精品国产电影| 免费h成人黄漫画嘿咻破解版| 亚洲免费一区二区| 亚洲AV无码成人精品区蜜桃| 亚洲欧洲精品久久| 中文字幕在线亚洲精品| 亚洲国产精品一区二区成人片国内| 亚洲国产精品婷婷久久| 亚洲中文字幕伊人久久无码| 亚洲国产精品va在线播放| 亚洲自偷自拍另类图片二区| 亚洲午夜理论片在线观看| 极品美女一级毛片免费| a毛片在线免费观看| 无码乱肉视频免费大全合集| 免费特级黄毛片在线成人观看 | 91香蕉国产线观看免费全集| 无码中文字幕av免费放dvd| 日韩精品亚洲专区在线观看| 无码国产精品一区二区免费vr | 免费国产高清毛不卡片基地| 国产黄色片免费看| 2022久久国产精品免费热麻豆|