Android Service在工作中也用的很多,但是AIDL就用的很少了,感覺也很生疏,之前在公司也有同事做過技術講座,而且也看過一些技術文章,但是感覺依然朦朦朧朧的。現在從事教學工作後,把AIDL又看了一遍,發現其實並不用理解的那麼複雜,其實很簡單的一個RPC(IPC)機制。
使用AIDL涉及到的前提是:需要跟其他應用的Service進行資料交換或者是方法調用。(也就是遠程操作其他Service)。否則如果沒有資料交換或方法調用,直接使用startService()即可;本地Service更加無需AIDL。
明確這個大前提後,來看AIDL所涉及的幾個知識點:
1.ServiceConnection介面:實現這個介面後可以實現Service串連狀態的回調方法onServiceConnected(ComponentName component, IBinder service)和onServiceDisconnected(ComponentName component)。
2.IBinder介面
3.Binder類:Binder可以想象成一個記憶體共用對象,這個對象只有方法暴露出來給用戶端調用。
4.Stub靜態內部類:其實就是繼承了Binder和實現了自己定義的AIDL介面的一個類(所謂的代理),就是一個實現了自己定義的介面的一個Binder。
5.實現了Parcelable序列化介面的自訂Java Bean:如果傳輸簡單資料,根本沒必要。(順便說兩句:1.要想把資料存放區到磁碟或者是通過網路傳輸,一定要序列化;2.最為經常使用的Bundle其實就是一個Parcelable,可以通過Bundle來理解Parcelable)
使用AIDL要注意的地方:
1.檔案名稱字一定要以.aidl結尾
2..aidl檔案的包名很重要,Service端和調用端包名一定要保持一致。
先上一張圖,說明整個調用過程和遠端程序呼叫的原理:
下面貼出工程代碼結構圖:
下面上代碼:
1.IPerson.aidl檔案:
[java]
- package com.wenix.service.aidl;
- /**
- *除了基本類型,String,List,Map,CharSequence以外,其他類型一定要導包,即時是同一包下。
- */
- import com.wenix.service.aidl.Person;
- interface IPerson{
- Person getPerson(in int id);
- }
2.Person.aidl檔案:(用來聲明序列化對象)
[java]
- package com.wenix.service.aidl;
-
- /**
- *這裡聲明Person類型的時候是小寫parcelable
- */
- parcelable Person;
3.PersonService.java檔案:(定義提供服務的Service,記住一定要在AndroidMenifest.xml檔案中註冊)
[java]
- package com.wenix.androidaidl;
-
- import com.wenix.service.aidl.IPerson;
- import com.wenix.service.aidl.Person;
-
- import android.app.Service;
- import android.content.Intent;
- import android.os.IBinder;
- import android.os.RemoteException;
-
- public class PersonService extends Service {
- //由於是遠程Service,所以用戶端肯定不能使用顯示Intent來啟動Service,所以必須提供ACTION。
- public static final String AIDL_ACTION = "com.wenix.intent.action.AIDL_ACTION";
- private PersonBinder personBinder;
- /**
- * 這裡繼承了自動產生的Stub靜態內部類,並提供了介面方法的實現。
- * @author wenix
- */
- public class PersonBinder extends IPerson.Stub{
- @Override
- public Person getPerson(int id) throws RemoteException {
- //這裡只返回了一個簡單的自訂對象,其實原理相同,任何複雜物件只要序列化了,都可以返回
- return new Person(id, "wenix", "wenix");
- }
- }
- @Override
- public IBinder onBind(Intent intent) {
- //此處返回提供給用戶端的Binder對象(記憶體共用對象)
- return personBinder;
- }
- @Override
- public void onCreate() {
- super.onCreate();
- //進行資料初始化
- personBinder = new PersonBinder();
- }
- }
4.用戶端代碼:(綁定遠程Service,然後擷取Binder對象,然後進行資料交換和方法調用)
[java]
- package com.wenix.androidclient;
-
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup.LayoutParams;
- import android.widget.Button;
- import android.widget.LinearLayout;
- import android.widget.TextView;
-
- import com.wenix.service.aidl.IPerson;
-
- public class MainActivity extends Activity {
- private static final String TAG = "MainActivity";
- private class PersonServiceConnection implements ServiceConnection{
- @Override
- public void onServiceConnected(ComponentName cmp, IBinder service) {
- //用戶端在這個回調方法中獲得Binder對象
- IPerson p = IPerson.Stub.asInterface(service);
- try {
- //這裡調用AIDL規定的介面來擷取資料
- Log.i(TAG, p.getPerson(1).toString());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
-
- }
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- //介面採用動態布局
- LinearLayout ll = new LinearLayout(this);
- ll.setOrientation(LinearLayout.VERTICAL);
- ll.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-
- LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
- Button btn = new Button(this);
- btn.setLayoutParams(params);
- btn.setText("擷取Service資料");
- btn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //啟動相應的Service,由於是遠程Service,所以不能使用顯示Intent
- Intent service = new Intent("com.wenix.intent.action.AIDL_SERVICE");
- PersonServiceConnection conn = new PersonServiceConnection();
- bindService(service, conn, Context.BIND_AUTO_CREATE);
- }
- });
- TextView tv = new TextView(this);
- tv.setLayoutParams(params);
- ll.addView(btn);
- ll.addView(tv);
- setContentView(ll);
- }
- }
工程徹底完成,然後我們運行後點擊Button,就可以看到擷取的資料:
只需掌握整個流程,AIDL就可以很容易的使用。後期會加入一些使用AIDL的具體執行個體。