Android進(jìn)程通信(IPC)之AIDL快速入門

本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布

“Android進(jìn)程通信”镶摘,乍一聽感覺好深?yuàn)W的東西。到底什么是進(jìn)程通信呢渴析?舉個(gè)栗子:現(xiàn)在我手機(jī)有兩個(gè)應(yīng)用程序梭稚,其中一個(gè)我們暫且叫它客戶端,它的功能是實(shí)現(xiàn)兩個(gè)數(shù)相加怨规,即當(dāng)你在界面中輸入兩個(gè)數(shù)陌宿,點(diǎn)一下計(jì)算的按鈕,就會(huì)得到兩個(gè)數(shù)相加的結(jié)果波丰。第二個(gè)應(yīng)用程序我們暫且叫它服務(wù)端壳坪,它是用來存放客戶端的具體邏輯的,即兩個(gè)數(shù)相加的具體計(jì)算過程在這個(gè)應(yīng)用程序中掰烟。我們?cè)诳蛻舳酥休斎雰蓚€(gè)數(shù)爽蝴,然后將這兩個(gè)數(shù)傳到服務(wù)端中,服務(wù)端經(jīng)過計(jì)算把兩個(gè)數(shù)的相加結(jié)果再傳回客戶端纫骑。這樣兩個(gè)應(yīng)用程序便實(shí)現(xiàn)了通信蝎亚。

Android實(shí)現(xiàn)進(jìn)程間的通信有四種方式,分別對(duì)應(yīng)于Android中的四大組件惧磺。即Activity颖对、Broadcast、ContentProvider磨隘、Service缤底。其中Activity可以通過Intent訪問其他進(jìn)程的Activity,Broadcast可以給Android系統(tǒng)中所有的應(yīng)用程序發(fā)送廣播,需要跨進(jìn)程通信的應(yīng)用程序可以監(jiān)聽這些廣播番捂,ContentProvider可以向其他應(yīng)用程序共享數(shù)據(jù)个唧,以及允許其他應(yīng)用程序?qū)ζ鋽?shù)據(jù)進(jìn)行增刪改查操作。最后便是本文的重點(diǎn)设预,通過Service利用AIDL進(jìn)行通信徙歼。

AIDL(Android Interface Definition Language)是一種接口定義語(yǔ)言,由于Android的每個(gè)進(jìn)程都運(yùn)行在獨(dú)立的虛擬機(jī)中,所以進(jìn)程之間通信會(huì)比較麻煩魄梯。我們可以利用AIDL將一個(gè)進(jìn)程的數(shù)據(jù)拆分成Android系統(tǒng)可識(shí)別的數(shù)據(jù)單元桨螺,然后系統(tǒng)再重新將數(shù)據(jù)單元合成傳遞給另一個(gè)進(jìn)程。這樣就實(shí)現(xiàn)了進(jìn)程間的通信酿秸。


那么我們?cè)撊绾问褂肁IDL呢灭翔?既然AIDL是一種接口定義語(yǔ)言,自然我們就得先定義好接口辣苏。具體的步驟如下:

1.創(chuàng)建.aidl文件
2.實(shí)現(xiàn)接口
3.將接口暴露給客戶端

接下來我們來通過本文開頭這個(gè)例子來具體講講如何通過以上三步就可以實(shí)現(xiàn)進(jìn)程間的通信肝箱。

第一步:創(chuàng)建.aidl文件

如上圖,新建一個(gè)Android工程稀蟋,然后添加一個(gè)模塊煌张。其中一個(gè)aidlclient作為客戶端,另一個(gè)app為服務(wù)端退客。先在app文件夾下建立一個(gè)與Java文件同級(jí)的文件夾命名為“aidl”骏融,再在這個(gè)文件夾下新建一個(gè)與該模塊同名的包尉尾,包下新建一個(gè)aidl接口妓肢。注意其擴(kuò)展名為aidl蔽莱。在該文件中我們便可以定義自己的接口砌溺,在上例中我們可以這樣定義:

package com.example.administrator.aidldemo;
interface IMyAidlInterface { 
  int add(int num1,int num2);
}

注:文件必須聲明包名套媚,且要和該服務(wù)端模塊的包名相同慈鸠。接口方法中的入?yún)⒅С只緮?shù)據(jù)類型逝段,除short外私股。因?yàn)槠錈o法被序列化

然后我們?cè)诳蛻舳薬idlclient模塊下新建一個(gè)與服務(wù)端中一模一樣的aidl文件夾刷允,注意客戶端中的aidl文件夾下的內(nèi)容必須保證和服務(wù)端的一致冤留,包括包名和具體的aidl文件。
然后我們編譯一下Android Studio树灶,在兩個(gè)模塊的
build-->generated-->source下生成一個(gè)aidl文件夾纤怒,且文件夾下的目錄如下圖所示則表示我們的aidl文件已經(jīng)創(chuàng)建成功

第二步:實(shí)現(xiàn)接口

在我們的服務(wù)端的模塊的Java文件夾下新建一個(gè)服務(wù)如下圖:

該服務(wù)類中的代碼如下

package com.example.administrator.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
public class IRemoteService extends Service {
    @Nullable    
    @Override    
    public IBinder onBind(Intent intent) { 
         return iBinder;    
    }    
   private IBinder iBinder = new IMyAidlInterface.Stub(){        
       @Override        
       public int add(int num1, int num2) throws RemoteException {
            return num1+num2;        
       }    
   };
}

其中如下代碼,我們通過調(diào)用編譯生成的IMyAidlInterface的Stub方法實(shí)現(xiàn)我們之前定義的接口天通,即完成了我們的第二步實(shí)現(xiàn)接口

private IBinder iBinder = new IMyAidlInterface.Stub(){
  @Override 
  public int add(int num1, int num2) throws RemoteException {
   return num1+num2; 
  } 
};

注:別忘了在AndroidManifest文件中注冊(cè)該Service

<service android:name=".IRemoteService"    
 android:process=":remote"   
 android:exported="true">
</service>

第三步:將接口暴露給客戶端

public IBinder onBind(Intent intent) {
 return iBinder; 
}

我們只要在IRomoteService中的onBind中返回我們實(shí)現(xiàn)好的接口泊窘。這樣一旦客戶端綁定該服務(wù)就會(huì)執(zhí)行onBind方法從而得到已實(shí)現(xiàn)好的接口∠窈客戶端得到該接口就可以調(diào)用接口中的add方法來實(shí)現(xiàn)加法的運(yùn)算烘豹。
接下來我們來看一下調(diào)用的具體過程:
首先我們將客戶端的界面先布置好:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent"    
android:layout_height="match_parent"    
android:orientation="vertical">    
<EditText        
android:gravity="center|right"        
android:id="@+id/et_num1"        
android:layout_width="match_parent"        
android:layout_height="wrap_content" />    
<TextView        
android:layout_width="match_parent"        
android:layout_height="wrap_content"        
android:text="+"        
android:textSize="24sp"        
android:layout_gravity="center"        
android:gravity="right|center"/>    
<EditText        
android:gravity="center|right"        
android:layout_width="match_parent"        
android:layout_height="wrap_content"        
android:id="@+id/et_num2"/>    
<TextView        
android:layout_width="match_parent"        
android:layout_height="wrap_content"        
android:text="="        
android:textSize="24sp"        
android:layout_gravity="center"        
android:gravity="right|center"/>    
<EditText        
android:gravity="center|right"        
android:editable="false"        
android:layout_width="match_parent"        
android:layout_height="wrap_content"        
android:id="@+id/edit_show_result"        
android:textSize="24sp"/>    
<Button        
android:layout_width="match_parent"        
android:layout_height="wrap_content"        
android:id="@+id/btn_count"        
android:text="遠(yuǎn)程計(jì)算"        
android:gravity="center"        
android:textSize="24sp" />
</LinearLayout>

界面非常簡(jiǎn)單在兩個(gè)EditText中輸入兩個(gè)數(shù)點(diǎn)擊按鈕,然后顯示計(jì)算結(jié)果诺祸。

接下來我們來看一下該界面的具體Java代碼:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText et_num1;
    private EditText et_num2;
    private EditText edit_show_result;
    private Button btn_count;
    private int mNum1;
    private int mNum2;
    private int mTotal;
    private IMyAidlInterface iMyAidlInterface;
    //綁定服務(wù)回調(diào)
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //服務(wù)綁定成功后調(diào)用携悯,獲取服務(wù)端的接口,這里的service就是服務(wù)端onBind返
            //回的iBinder即已實(shí)現(xiàn)的接口
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            //解除綁定時(shí)調(diào)用筷笨,清空接口憔鬼,防止內(nèi)容溢出        
            iMyAidlInterface = null;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {        
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.activity_main);    
        bindService();   
        initView();
    }
    //初始化界面
    private void initView(){
        et_num1 = (EditText)findViewById(R.id.et_num1);    
        et_num2 = (EditText)findViewById(R.id.et_num2);    
        edit_show_result = (EditText)findViewById(R.id.edit_show_result);    
        btn_count = (Button)findViewById(R.id.btn_count);        
        btn_count.setOnClickListener(this);
    }
    //按鈕點(diǎn)擊事件
    private void handleBtnClickEvent(){
        mNum1 = Integer.parseInt(et_num1.getText().toString());    
        mNum2 = Integer.parseInt(et_num2.getText().toString());    
        try {        
            mTotal = iMyAidlInterface.add(mNum1,mNum2);    
        } catch (RemoteException e) { 
           e.printStackTrace();    
        }    
        edit_show_result.setText(mTotal+"");
    }
    //綁定服務(wù)
    private void bindService(){  
        Intent intent = new Intent();    
        intent.setComponent(newComponentName("com.example.administrator.aidldemo",  
          "com.example.administrator.aidldemo.IRemoteService"));   
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
    }
    @Override
    public void onClick(View v) { 
       handleBtnClickEvent();   
     }    
    protected void onDestroy(){    
        super.onDestroy();
        //當(dāng)活動(dòng)銷毀時(shí)解除綁定        
        unbindService(conn);    
    }
}

其實(shí)上面的代碼還是很好理解的龟劲,當(dāng)啟動(dòng)客戶端,將會(huì)執(zhí)行bindService方法轴或,去綁定服務(wù)端的遠(yuǎn)程服務(wù)昌跌,一旦綁定成功,就會(huì)回調(diào)conn 中的onServiceConnected方法照雁。在方法中避矢,我們獲取到了服務(wù)端實(shí)現(xiàn)好的接口。即服務(wù)端將該實(shí)現(xiàn)好的接口暴漏給了客戶端囊榜。
然后當(dāng)我們輸入兩個(gè)數(shù),點(diǎn)擊按鈕時(shí)亥宿,就可以調(diào)用我們剛得到的接口的add方法卸勺,來實(shí)現(xiàn)兩個(gè)加數(shù)的相加運(yùn)算。

這樣我們就完成整個(gè)例子的編碼烫扼,接下來我們就來運(yùn)行下曙求。
先運(yùn)行服務(wù)端的模塊,再運(yùn)行客戶端的映企。

服務(wù)端應(yīng)用程序
客戶端應(yīng)用程序

好了悟狱,這篇先就講這么多,下一篇Android進(jìn)程通信(IPC)之AIDL對(duì)象傳遞主要講解了如何在AIDL中傳遞對(duì)象堰氓。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末挤渐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子双絮,更是在濱河造成了極大的恐慌浴麻,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囤攀,死亡現(xiàn)場(chǎng)離奇詭異软免,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)焚挠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門膏萧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蝌衔,你說我怎么就攤上這事榛泛。” “怎么了胚委?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵挟鸠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我亩冬,道長(zhǎng)艘希,這世上最難降的妖魔是什么硼身? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮覆享,結(jié)果婚禮上佳遂,老公的妹妹穿的比我還像新娘。我一直安慰自己撒顿,他們只是感情好丑罪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凤壁,像睡著了一般吩屹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拧抖,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天煤搜,我揣著相機(jī)與錄音,去河邊找鬼唧席。 笑死擦盾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的淌哟。 我是一名探鬼主播迹卢,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼徒仓!你這毒婦竟也來了腐碱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤蓬衡,失蹤者是張志新(化名)和其女友劉穎喻杈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狰晚,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筒饰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壁晒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓷们。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖秒咐,靈堂內(nèi)的尸體忽然破棺而出谬晕,到底是詐尸還是另有隱情,我是刑警寧澤携取,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布攒钳,位于F島的核電站,受9級(jí)特大地震影響雷滋,放射性物質(zhì)發(fā)生泄漏不撑。R本人自食惡果不足惜文兢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焕檬。 院中可真熱鬧姆坚,春花似錦、人聲如沸实愚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腊敲。三九已至击喂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碰辅,已是汗流浹背茫负。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人潮尝。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓榕吼,卻偏偏與公主長(zhǎng)得像勉失,于是被迫代替她去往敵國(guó)和親羹蚣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

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