1、IPCjava
inter process communication 進程間通信android
2、AIDLapp
android interface defination language 安卓接口定義語言框架
知足兩個進程之間 接口數據的交換(ipc)ide
首先咱們搞清楚兩個概念 遠程服務和本地服務 ?佈局
本地服務:服務的代碼在應用程序工程的內部this
遠程服務:服務的代碼在另外一個應用程序的裏面spa
3、下面經過案例說明AIDL(IPC)在遠程服務中使用3d
1.首先建立一個Android項目,命名爲"遠程服務";代理
(1)工程一欄表以下:
(2)既然是遠程服務,咱們就先建立遠程服務爲RemoteServiceDemo.java,同時也須要在AndroidMainfest.xml的清單文件中註冊,以下:
AndroidMainfest.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.himi.remoteservice" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="15" 9 android:targetSdkVersion="17" /> 10 11 <application 12 android:allowBackup="true" 13 android:icon="@drawable/ic_launcher" 14 android:label="@string/app_name" 15 android:theme="@style/AppTheme" > 16 <activity 17 android:name=".MainActivity" 18 android:label="@string/app_name" > 19 <intent-filter> 20 <action android:name="android.intent.action.MAIN" /> 21 22 <category android:name="android.intent.category.LAUNCHER" /> 23 </intent-filter> 24 </activity> 25 <service android:name="com.himi.remoteservice.RemoteServiceDemo"> 26 <intent-filter > 27 <action android:name="com.himi.remoteservice"/> 28 </intent-filter> 29 </service> 30 </application> 31 32 </manifest>
這裏咱們定義了service的action,這是由於假若應用程序本身調用服務,直接使用顯式意圖便可,也就是以下這種形式:
Intent intent = new Intent(this,Service.class);
startActivity(intent);
可是,咱們這裏是本身定義的遠程服務程序,也就是這個程序在遠程,讓本地(或者其餘用戶)去調用的,因此這裏使用了隱式意圖。
與此同時,咱們編寫RemoteServiceDemo.java代碼以下:
1 package com.himi.remoteservice; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.Binder; 6 import android.os.IBinder; 7 8 public class RemoteServiceDemo extends Service { 9 10 private class MyBinder extends Binder implements IService { 11 12 public void callMethodInService() { 13 methodInservice(); 14 15 } 16 17 } 18 19 @Override 20 public IBinder onBind(Intent intent) { 21 System.out.println("遠程的服務被綁定 onBind"); 22 return new MyBinder(); 23 } 24 25 @Override 26 public boolean onUnbind(Intent intent) { 27 System.out.println("遠程的服務被解除綁定 onUnbind"); 28 return super.onUnbind(intent); 29 } 30 31 @Override 32 public void onCreate() { 33 System.out.println("遠程的服務onCreate"); 34 super.onCreate(); 35 } 36 37 @Override 38 public void onDestroy() { 39 System.out.println("遠程的服務onDestroy"); 40 super.onDestroy(); 41 } 42 43 public void methodInservice() { 44 System.out.println("我是遠程服務裏面的方法,我被調用了"); 45 } 46 }
這裏咱們定義的methodInservice(),是遠程服務中的方法,這也是本地用戶(或者其餘用戶)但願調用和訪問的方法。
如今咱們的需求,就是能夠由別的用戶程序調用這個methodInservice()方法。
上面接口IService.java爲以下:
1 package com.himi.remoteservice; 2 3 public interface IService { 4 5 public void callMethodInService(); 6 }
(3)其餘的MainActivity和activity_main佈局文件咱們這裏沒有修改
(4)這樣一個遠程的服務就搭建好了
工程一覽表以下:
2.接下來咱們再新建一個Android項目,命名爲" 調用遠程服務的方法 ",以下:
(1)項目一覽表:
(2)先編寫佈局文件activity_main.xml,以下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 tools:context="com.himi.remotecall.MainActivity" > 7 8 <Button 9 android:onClick="bind" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:text="綁定遠程服務" /> 13 <Button 14 android:onClick="call" 15 android:layout_width="match_parent" 16 android:layout_height="wrap_content" 17 android:text="調用遠程服務方法" /> 18 19 </LinearLayout>
佈局效果以下:
(3)實現一下MainActivity裏面的代碼,以下:
1 package com.himi.remotecall; 2 3 import android.app.Activity; 4 import android.content.ComponentName; 5 import android.content.Intent; 6 import android.content.ServiceConnection; 7 import android.os.Bundle; 8 import android.os.IBinder; 9 import android.view.View; 10 11 public class MainActivity extends Activity { 12 private MyConn conn; 13 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 setContentView(R.layout.activity_main); 18 } 19 20 /** 21 * 綁定遠程服務 22 * @param view 23 */ 24 public void bind(View view) { 25 Intent service = new Intent(); 26 service.setAction("com.himi.remoteservice"); 27 conn = new MyConn(); 28 bindService(service, conn, BIND_AUTO_CREATE); 29 } 30 31 private class MyConn implements ServiceConnection { 32 33 public void onServiceConnected(ComponentName name, IBinder service) { 34 35 } 36 37 public void onServiceDisconnected(ComponentName name) { 38 39 } 40 41 } 42 43 public void call(View view) { 44 45 } 46 }
這個客戶端訪問遠程服務的框架,咱們搭建好了;
可是咱們不能訪問遠端的服務方法,由於這裏的
public void onServiceConnected(ComponentName name, IBinder service),這個方法是綁定服務成功的時候調用的,Service.java會反饋一個IBinder service的信息,可是咱們這裏並不像遠程服務那樣,具有這個IService的接口,經過接口類型轉化,也就是以下:
IService iService = (IService)service;
iService.callMethodInService();
如今不能這樣調用methodInservice()方法,由於根本就不能接收到 IBinder service
因此不能調用遠程服務的methodInservice()方法。
3.該怎麼辦?如何調用遠程服務方法?這裏要利用到AIDL(IPC)
(1)第一步,咱們回到"遠程服務」的項目,以下:
IService.java文件在工程目錄下的路徑,以下:
找到這個路徑以下:
看到上面的IService.java文件了,這裏咱們修改它的擴展名,由java 改爲 aidl,以下:
回到"遠程服務"這個工程,刷新它,結果以下:
這會咱們發現這裏的IService.java變成了IService.aidl,可是報錯了,不用擔憂咱們慢慢修改錯誤;
(2)來到IService.aidl文件下,以下:
aidl做爲兩個進程之間的接口,固然是共有的,不是共有的沒法互相通訊了,這裏aidl中沒有權限修飾符,因此刪除上下兩個public,結果以下:
如今IService.aidl文件也就不報錯了;
(3)接着,咱們來到RemoteServiceDemo.java以下:
修改爲以下形式,便可:
爲何這樣修改?
相應咱們在gen目錄下,生成一個IService.java,以下:
由於IService.Stub在gen目錄下生成的IService.java的實現了接口com.himi.remoteservice.IService,同時繼承了android.os.Binder,以下:
1 /* 2 * This file is auto-generated. DO NOT MODIFY. 3 * Original file: C:\\Users\\Administrator.GDIZOK2X2LA0SQG\\workspace\\遠程服務\\src\\com\\himi\\remoteservice\\IService.aidl 4 */ 5 package com.himi.remoteservice; 6 public interface IService extends android.os.IInterface 7 { 8 /** Local-side IPC implementation stub class. */ 9 public static abstract class Stub extends android.os.Binder implements com.himi.remoteservice.IService 10 { 11 private static final java.lang.String DESCRIPTOR = "com.himi.remoteservice.IService"; 12 /** Construct the stub at attach it to the interface. */ 13 public Stub() 14 { 15 this.attachInterface(this, DESCRIPTOR); 16 } 17 /** 18 * Cast an IBinder object into an com.himi.remoteservice.IService interface, 19 * generating a proxy if needed. 20 */ 21 public static com.himi.remoteservice.IService asInterface(android.os.IBinder obj) 22 { 23 if ((obj==null)) { 24 return null; 25 } 26 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 27 if (((iin!=null)&&(iin instanceof com.himi.remoteservice.IService))) { 28 return ((com.himi.remoteservice.IService)iin); 29 } 30 return new com.himi.remoteservice.IService.Stub.Proxy(obj); 31 } 32 @Override public android.os.IBinder asBinder() 33 { 34 return this; 35 } 36 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 37 { 38 switch (code) 39 { 40 case INTERFACE_TRANSACTION: 41 { 42 reply.writeString(DESCRIPTOR); 43 return true; 44 } 45 case TRANSACTION_callMethodInService: 46 { 47 data.enforceInterface(DESCRIPTOR); 48 this.callMethodInService(); 49 reply.writeNoException(); 50 return true; 51 } 52 } 53 return super.onTransact(code, data, reply, flags); 54 } 55 private static class Proxy implements com.himi.remoteservice.IService 56 { 57 private android.os.IBinder mRemote; 58 Proxy(android.os.IBinder remote) 59 { 60 mRemote = remote; 61 } 62 @Override public android.os.IBinder asBinder() 63 { 64 return mRemote; 65 } 66 public java.lang.String getInterfaceDescriptor() 67 { 68 return DESCRIPTOR; 69 } 70 @Override public void callMethodInService() throws android.os.RemoteException 71 { 72 android.os.Parcel _data = android.os.Parcel.obtain(); 73 android.os.Parcel _reply = android.os.Parcel.obtain(); 74 try { 75 _data.writeInterfaceToken(DESCRIPTOR); 76 mRemote.transact(Stub.TRANSACTION_callMethodInService, _data, _reply, 0); 77 _reply.readException(); 78 } 79 finally { 80 _reply.recycle(); 81 _data.recycle(); 82 } 83 } 84 } 85 static final int TRANSACTION_callMethodInService = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 86 } 87 public void callMethodInService() throws android.os.RemoteException; 88 }
(4)這樣"遠端服務",咱們就修改好了,以下潔白無瑕:
4. 接着回到"調用遠程服務的方法」這個項目下:
(1)在src目錄下,建立一個包名,這個包名要 和 遠程服務下的RemoteServiceDemo.java的包名一致, 這裏都是com.himi.remoteservice,以下:
(2)把工程"遠程服務"中的IService.aidl 複製到 工程」調用遠程服務的方法"的src/com.himi.remoteservice,以下:
工程」調用遠程服務的方法"的gen目錄下也生成了IService.java
(3)回到工程」調用遠程服務的方法"的MainActivity,編寫代碼以下:
1 package com.himi.remotecall; 2 3 import com.himi.remoteservice.IService; 4 5 import android.app.Activity; 6 import android.content.ComponentName; 7 import android.content.Intent; 8 import android.content.ServiceConnection; 9 import android.os.Bundle; 10 import android.os.IBinder; 11 import android.os.RemoteException; 12 import android.view.View; 13 14 public class MainActivity extends Activity { 15 private MyConn conn; 16 private IService iservice; 17 @Override 18 protected void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 } 22 23 /** 24 * 綁定遠程服務 25 * @param view 26 */ 27 public void bind(View view) { 28 Intent service = new Intent(); 29 service.setAction("com.himi.remoteservice"); 30 conn = new MyConn(); 31 bindService(service, conn, BIND_AUTO_CREATE); 32 } 33 34 private class MyConn implements ServiceConnection { 35 36 public void onServiceConnected(ComponentName name, IBinder service) { 37 iservice = IService.Stub.asInterface(service); 38 } 39 40 public void onServiceDisconnected(ComponentName name) { 41 42 } 43 44 } 45 46 public void call(View view) { 47 try { 48 iservice.callMethodInService(); 49 } catch (RemoteException e) { 50 // TODO 自動生成的 catch 塊 51 e.printStackTrace(); 52 } 53 } 54 }
(4)佈署程序到模擬器上演示:
首先佈署"遠端服務" 到模擬器上,以下:
最小化 "遠程服務", 而後佈署" 調用遠程服務的方法"到模擬器上,以下:
接下咱們點擊 按鈕----綁定遠程服務 ,觀察logcat打印的日誌,以下:
這兩條日誌是 工程"遠程服務"中的RemoteServiceDemo中打印的;
咱們再點擊屢次這個 按鈕----調用遠程服務的方法 ,在觀察logcat打印的日誌,以下:
這兩條日誌是 工程"調用遠程服務的方法"中的MainActivity中call點擊事件,調用工程「遠程服務」中RemoteServiceDemo的methodInservice()方法打印的;以下:
4、使用 AIDL 遠程服務綁定調用的步驟:
(1)採用bind的方法綁定開啓服務。
Intent intent = new Intent();//隱式的意圖
intent.setAction("action");
bindService(intent, conn, BIND_AUTO_CREATE);
(2) .java的接口文件改爲.aidl文件,刪除public 訪問修飾符。
(3) 在工程目錄gen目錄下會自動編譯生成IService.java的接口文件
生成的IService.java,是經過aidl文件生成的。服務的中間人想暴露什麼方法,就怎麼定義接口
(4) 遠程服務代碼爲private class MyBinder extends IService.Stub
同時在返回代理人對象,以下:
public IBinder onBind(Intent intent){……}
(5)實現ServiceConnection接口裏面的方法
private class MyConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IService.Sub.asInterface(service);
System.out.println("Activity,獲得代理人對象");
}
注意:iService = IService.Stub.asInterface(service)
(6) iService.callMethodInService();