Android使用AIDL實現進程間通信

Android的每個應用程序都是一個不同的進程,在Android平臺一個進程通常不能訪問另一個進程的內存空間。
比如一個應用程序有兩個進程,一個進程負責UI的展示,而另一個進程(通常是在此進程中使用一個service)用來進行網絡資源的請求,需要主進程和服務進程之間進行數據的傳遞。(微信就是使用的這種機制)
Android提供瞭AIDL來實現進程間通信(IPC),AIDL全稱為Android Interface Definition Language。

AIDL IPC機制是面向接口的,使用代理類在客戶端和服務端之間進行數據傳遞。

 

使用AIDL實現IPC服務需要分別實現服務端和客戶端。實例源碼下載:點擊下載

 

 

服務端:

 

1、新建aidl文件定義服務端和客戶端交互的接口(包括數據接口);
adil文件定義規范:
在服務端的src目錄下新建以.aidl為後綴的文件,在這個文件中定義接口,聲明服務端和客戶端交互的api,語法和普通java接口聲明一樣,可以添加中英文註釋。
區別:
a、除瞭Java基本數據類型 (int, long, char, boolean等)、String、CharSequence、List、Map外,其他復雜類型都需要顯式import(包括其他AIDL定義的接口),即便是在同一個包內定義。
b、支持泛型實例化的List,如List<String>;不支持泛型實例化的Map,如Map<String, String>。對於List為參數接收者接收到的始終是ArrayList;對於Map為參數接收者接收到的始終是HashMap。
c、interface和函數都不能帶訪問權限修飾符。
d、接口內隻允許定義方法,不允許定義靜態屬性。

 

[java]
package com.snail.test.aidl.server; 
 
import com.snail.test.aidl.server.Person; 
interface IAIDLServerService { 
 
     Person getPerson(); 

package com.snail.test.aidl.server;

import com.snail.test.aidl.server.Person;
interface IAIDLServerService {

     Person getPerson();
}aidl文件新建完成後,adt工具會自動編譯aidl文件,大傢可以在gen目錄看到對應的java文件。
文件中主要有:
a、抽象類Stub,繼承Binder實現自定義接口,作用同進程內通信服務中自定義的Binder,客戶端通過它對服務進行調用。
b、靜態類Proxy,實現自定義接口,代理模式接收對Stub的調用。

 

2、新建service實現定義的接口。

接口中傳遞的對象數據需要實現序列化接口,並且也要定義aidl文件。

[java]
public class AIDLServerService extends Service { 
 
    /**
     * 返回綁定
     */ 
    @Override 
    public IBinder onBind(Intent intent) { 
        return mBinder; 
    } 
 
    /**
     * 初始化根據AIDL文件生成的Stub
     */ 
    private IAIDLServerService.Stub mBinder = new Stub() { 
 
        /**
         * 實現定義的接口
         */ 
        public Person getPerson() throws RemoteException { 
            Person mBook = new Person(); 
            mBook.setName("Snail"); 
            mBook.setAge(27); 
            return mBook; 
        } 
    }; 
 

public class AIDLServerService extends Service {

 /**
  * 返回綁定
  */
 @Override
 public IBinder onBind(Intent intent) {
  return mBinder;
 }

 /**
  * 初始化根據AIDL文件生成的Stub
  */
 private IAIDLServerService.Stub mBinder = new Stub() {

  /**
   * 實現定義的接口
   */
  public Person getPerson() throws RemoteException {
   Person mBook = new Person();
   mBook.setName("Snail");
   mBook.setAge(27);
   return mBook;
  }
 };

}
客戶端:
1、在工程中定義服務端和客戶端交互的接口,跟服務端的一模一樣,包名也要一樣,不然會報錯java.lang.SecurityException: Binder invocation to an incorrect interface。

 


2、通過Stub.asInterface方法獲取服務來使用定義的接口實現進程間的通信。

[java]
public class MainActivity extends Activity { 
 
    private Button mAIDLBtn; 
    private TextView mAIDLView; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        mAIDLBtn = (Button) findViewById(R.id.aidl_btn); 
        mAIDLView = (TextView) findViewById(R.id.aidl_text); 
 
        mAIDLBtn.setOnClickListener(new OnClickListener() { 
            public void onClick(View v) { 
                // 綁定服務,這裡的service action非常重要,要跟server端定義的action一致  
                Intent service = new Intent( 
                        "com.snail.test.aidl.server.AIDLServerService"); 
                bindService(service, mConnection, BIND_AUTO_CREATE); 
            } 
 
        }); 
    } 
 
    private IAIDLServerService mIaidlServerService = null; 
 
    /**
     * 服務連接
     */ 
    private ServiceConnection mConnection = new ServiceConnection() { 
 
        public void onServiceDisconnected(ComponentName name) { 
            mIaidlServerService = null; 
        } 
 
        /**
         * 服務連接成功
         */ 
        public void onServiceConnected(ComponentName name, IBinder service) { 
            mIaidlServerService = IAIDLServerService.Stub.asInterface(service); 
            // aidl實現進程間通信  
            try { 
                Person person = mIaidlServerService.getPerson(); 
                String str = "姓名:" + person.getName() + "\n" + "年齡:" 
                        + person.getAge(); 
                mAIDLView.setText(str); 
            } catch (RemoteException e) { 
                e.printStackTrace(); 
            } 
        } 
    }; 

public class MainActivity extends Activity {

 private Button mAIDLBtn;
 private TextView mAIDLView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mAIDLBtn = (Button) findViewById(R.id.aidl_btn);
  mAIDLView = (TextView) findViewById(R.id.aidl_text);

  mAIDLBtn.setOnClickListener(new OnClickListener() {
   public void onClick(View v) {
    // 綁定服務,這裡的service action非常重要,要跟server端定義的action一致
    Intent service = new Intent(
      "com.snail.test.aidl.server.AIDLServerService");
    bindService(service, mConnection, BIND_AUTO_CREATE);
   }

  });
 }

 private IAIDLServerService mIaidlServerService = null;

 /**
  * 服務連接
  */
 private ServiceConnection mConnection = new ServiceConnection() {

  public void onServiceDisconnected(ComponentName name) {
   mIaidlServerService = null;
  }

  /**
   * 服務連接成功
   */
  public void onServiceConnected(ComponentName name, IBinder service) {
   mIaidlServerService = IAIDLServerService.Stub.asInterface(service);
   // aidl實現進程間通信
   try {
    Person person = mIaidlServerService.getPerson();
    String str = "姓名:" + person.getName() + "\n" + "年齡:"
      + person.getAge();
    mAIDLView.setText(str);
   } catch (RemoteException e) {
    e.printStackTrace();
   }
  }
 };
}
客戶端和服務端的service生命周期:

客戶端通過bindService綁定服務,若服務未啟動,會先執行Service的onCreate函數,再執行onBind函數,最後執行ServiceConnection對象的onServiceConnected函數,客戶端可以自動啟動服務。若服務已啟動但尚未綁定,先執行onBind函數,再執行ServiceConnection對象的onServiceConnected函數。若服務已綁定成功,則直接返回。

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *