关闭

看过的写的比较好的service之AIDL

317人阅读 评论(0) 收藏 举报
分类:

本文将以一个例子来和你分享使用AIDL的基础技能,这个例子里有:

1、一个类mAIDLActivity,继承Activity。里面有三个按钮,text分别为StartService,StopService,CallbackTest。

2、一个类mAIDLService,继承Service。为了充分展示ADIL的功能,它做以下工作:当用户点击CallbackTest按钮时,从mAIDLActivity调用mAIDLService中的Stub 对象的一个方法invokCallBack(),而这个方法又会调用mAIDLActivity中Stub 对象的一个方法performAction(),这个方法在屏幕上显示一个toast。没什么意义,只是展示一下AIDL如何使用。

3、两个AIDL文件:forService.aidl和forActivity.aidl。对应名字,在Service和Activity中分别有对象需要用到它们定义的接口。

    

开发环境为Eclipse。

拣重要的先说,来看看aidl文件的内容:

文件:forActivity.aidl

 

  1. package com.styleflying.AIDL;  
  2. interface forActivity  
  3.     void performAction();  
  4.      
 

文件:forService.aidl

 

  1. package com.styleflying.AIDL;  
  2. import com.styleflying.AIDL.forActivity;  
  3. interface forService  
  4.     void registerTestCall(forActivity cb);  
  5.     void invokCallBack();  
  6.  
 

这两个文件和Java文件放置的地方一样,看包名。

在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。为了方便手头无法演练的读者,代码贴上,不用细看。

文件forActivity.java:

 

  1.   
  2. package com.styleflying.AIDL;  
  3. import java.lang.String;  
  4. import android.os.RemoteException;  
  5. import android.os.IBinder;  
  6. import android.os.IInterface;  
  7. import android.os.Binder;  
  8. import android.os.Parcel;  
  9. public interface forActivity extends android.os.IInterface  
  10.  
  11.   
  12. public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forActivity  
  13.  
  14. private static final java.lang.String DESCRIPTOR "com.styleflying.AIDL.forActivity" 
  15.   
  16. public Stub()  
  17.  
  18. this.attachInterface(thisDESCRIPTOR);  
  19.  
  20.   
  21. public static com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)  
  22.  
  23. if ((obj==null))  
  24. return null 
  25.  
  26. android.os.IInterface iin (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
  27. if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forActivity)))  
  28. return ((com.styleflying.AIDL.forActivity)iin);  
  29.  
  30. return new com.styleflying.AIDL.forActivity.Stub.Proxy(obj);  
  31.  
  32. 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_performAction:  
  46.  
  47. data.enforceInterface(DESCRIPTOR);  
  48. this.performAction();  
  49. reply.writeNoException();  
  50. return true 
  51.  
  52.  
  53. return super.onTransact(code, data, reply, flags);  
  54.  
  55. private static class Proxy implements com.styleflying.AIDL.forActivity  
  56.  
  57. private android.os.IBinder mRemote;  
  58. Proxy(android.os.IBinder remote)  
  59.  
  60. mRemote remote;  
  61.  
  62. public android.os.IBinder asBinder()  
  63.  
  64. return mRemote;  
  65.  
  66. public java.lang.String getInterfaceDescriptor()  
  67.  
  68. return DESCRIPTOR;  
  69.  
  70. public void performAction() 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_performAction, _data, _reply, 0);  
  77. _reply.readException();  
  78.  
  79. finally  
  80. _reply.recycle();  
  81. _data.recycle();  
  82.  
  83.  
  84.  
  85. static final int TRANSACTION_performAction (IBinder.FIRST_CALL_TRANSACTION 0);  
  86.  
  87. public void performAction() throws android.os.RemoteException;  
  88.  

文件forService.java:

 

  1.   
  2. package com.styleflying.AIDL;  
  3. import java.lang.String;  
  4. import android.os.RemoteException;  
  5. import android.os.IBinder;  
  6. import android.os.IInterface;  
  7. import android.os.Binder;  
  8. import android.os.Parcel;  
  9. public interface forService extends android.os.IInterface  
  10.  
  11.   
  12. public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forService  
  13.  
  14. private static final java.lang.String DESCRIPTOR "com.styleflying.AIDL.forService" 
  15.   
  16. public Stub()  
  17.  
  18. this.attachInterface(thisDESCRIPTOR);  
  19.  
  20.   
  21. public static com.styleflying.AIDL.forService asInterface(android.os.IBinder obj)  
  22.  
  23. if ((obj==null))  
  24. return null 
  25.  
  26. android.os.IInterface iin (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
  27. if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forService)))  
  28. return ((com.styleflying.AIDL.forService)iin);  
  29.  
  30. return new com.styleflying.AIDL.forService.Stub.Proxy(obj);  
  31.  
  32. 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_registerTestCall:  
  46.  
  47. data.enforceInterface(DESCRIPTOR);  
  48. com.styleflying.AIDL.forActivity _arg0;  
  49. _arg0 com.styleflying.AIDL.forActivity.Stub.asInterface(data.readStrongBinder());  
  50. this.registerTestCall(_arg0);  
  51. reply.writeNoException();  
  52. return true 
  53.  
  54. case TRANSACTION_invokCallBack:  
  55.  
  56. data.enforceInterface(DESCRIPTOR);  
  57. this.invokCallBack();  
  58. reply.writeNoException();  
  59. return true 
  60.  
  61.  
  62. return super.onTransact(code, data, reply, flags);  
  63.  
  64. private static class Proxy implements com.styleflying.AIDL.forService  
  65.  
  66. private android.os.IBinder mRemote;  
  67. Proxy(android.os.IBinder remote)  
  68.  
  69. mRemote remote;  
  70.  
  71. public android.os.IBinder asBinder()  
  72.  
  73. return mRemote;  
  74.  
  75. public java.lang.String getInterfaceDescriptor()  
  76.  
  77. return DESCRIPTOR;  
  78.  
  79. public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException  
  80.  
  81. android.os.Parcel _data android.os.Parcel.obtain();  
  82. android.os.Parcel _reply android.os.Parcel.obtain();  
  83. try  
  84. _data.writeInterfaceToken(DESCRIPTOR);  
  85. _data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));  
  86. mRemote.transact(Stub.TRANSACTION_registerTestCall, _data, _reply, 0);  
  87. _reply.readException();  
  88.  
  89. finally  
  90. _reply.recycle();  
  91. _data.recycle();  
  92.  
  93.  
  94. public void invokCallBack() throws android.os.RemoteException  
  95.  
  96. android.os.Parcel _data android.os.Parcel.obtain();  
  97. android.os.Parcel _reply android.os.Parcel.obtain();  
  98. try  
  99. _data.writeInterfaceToken(DESCRIPTOR);  
  100. mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);  
  101. _reply.readException();  
  102.  
  103. finally  
  104. _reply.recycle();  
  105. _data.recycle();  
  106.  
  107.  
  108.  
  109. static final int TRANSACTION_registerTestCall (IBinder.FIRST_CALL_TRANSACTION 0);  
  110. static final int TRANSACTION_invokCallBack (IBinder.FIRST_CALL_TRANSACTION 1);  
  111.  
  112. public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException;  
  113. public void invokCallBack() throws android.os.RemoteException;  
  114.  

两段代码差不多,前面基本一样,从后面看,最后跟着我们在AIDL中自定义的方法,没有实现。两个文件各定义一个了接口,这两个接口分别会在Activity和Service中使用,在那里我们将实现自定义的方法。两个接口中都定义了一个抽象类Stub,实现所在的接口。Stub中又有一个类Proxy。Stub中有一个static的asInterface()方法,里面有很多return语句,在mAIDLActivity中调用它时,它返回一个新创建的内部类Proxy对象。

这个Stub对我们来说很有用,它继承了Binder。Binder有什么用呢?一个类,继承了Binder,那么它的对象就可以被远程的进程使用了(前提是远程进程获取了这个类的对象【对象的引用】,至于如如何获得看下文),在本例中就是说,如果一个Service中有一个继承了Stub的类的对象,那么这个对象中的方法就可以在Activity中使用,对Activity也是这样。至于Binder的细节,网上有很多贴介绍,看不明白也不影响我们完成这个例子。

再看mAIDLActivity.java:

 

  1. package com.styleflying.AIDL;  
  2. import android.app.Activity;  
  3. import android.content.ComponentName;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.content.ServiceConnection;  
  7. import android.os.Bundle;  
  8. import android.os.IBinder;  
  9. import android.os.RemoteException;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12. import android.view.View.OnClickListener;  
  13. import android.widget.Button;  
  14. import android.widget.Toast;  
  15. public class mAIDLActivity extends Activity  
  16.     private static final String TAG "AIDLActivity" 
  17.     private Button btnOk;  
  18.     private Button btnCancel;  
  19.     private Button btnCallBack;  
  20.       
  21.     private void Log(String str)  
  22.         Log.d(TAG, "------ " str "------");  
  23.          
  24.       
  25.     private forActivity mCallback new forActivity.Stub()  
  26.         public void performAction() throws RemoteException  
  27.          
  28.             Toast.makeText(mAIDLActivity.this"this toast is called from service"1).show();  
  29.          
  30.         };  
  31.           
  32.     forService mService;  
  33.     private ServiceConnection mConnection new ServiceConnection()  
  34.         public void onServiceConnected(ComponentName className,  
  35.                 IBinder service)  
  36.             mService forService.Stub.asInterface(service);  
  37.             try  
  38.                 mService.registerTestCall(mCallback);}  
  39.             catch (RemoteException e)  
  40.                   
  41.              
  42.              
  43.         public void onServiceDisconnected(ComponentName className)  
  44.             Log("disconnect service");  
  45.             mService null 
  46.              
  47.         };  
  48.     @Override  
  49.     public void onCreate(Bundle icicle)  
  50.         super.onCreate(icicle);  
  51.         setContentView(R.layout.main);  
  52.         btnOk (Button)findViewById(R.id.btn_ok);  
  53.         btnCancel (Button)findViewById(R.id.btn_cancel);  
  54.         btnCallBack (Button)findViewById(R.id.btn_callback);  
  55.         btnOk.setOnClickListener(new OnClickListener()  
  56.             public void onClick(View v)  
  57.                 Bundle args new Bundle();  
  58.                 Intent intent new Intent(mAIDLActivity.thismAIDLService.class);  
  59.                 intent.putExtras(args);  
  60.                 bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
  61.                 startService(intent);  
  62.                  
  63.             });  
  64.         btnCancel.setOnClickListener(new OnClickListener()  
  65.             public void onClick(View v)  
  66.                 unbindService(mConnection);  
  67.                 //stopService(intent);   
  68.                  
  69.             });  
  70.         btnCallBack.setOnClickListener(new OnClickListener()  
  71.               
  72.             @Override  
  73.             public void onClick(View v)  
  74.              
  75.                 try  
  76.                  
  77.                     mService.invokCallBack();  
  78.                 catch (RemoteException e)  
  79.                  
  80.                     // TODO Auto-generated catch block   
  81.                     e.printStackTrace();  
  82.                  
  83.              
  84.         });  
  85.          
  86.  

 

很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);给mService赋值了,这个mService是一个forService,而service是onServiceConnected()传进来的参数,onServiceConnected()会在连接Service的时候被系统调用,这个service参数的值来自哪里呢?看mAIDLService.java:

 

  1. package com.styleflying.AIDL;  
  2. import android.app.Service;  
  3. import android.content.Intent;  
  4. import android.os.IBinder;  
  5. import android.os.RemoteCallbackList;  
  6. import android.os.RemoteException;  
  7. import android.util.Log;  
  8. public class mAIDLService extends Service  
  9.     private static final String TAG "AIDLService"   
  10.     private forActivity callback;  
  11.     private void Log(String str)  
  12.         Log.d(TAG, "------ " str "------");  
  13.      
  14.     @Override  
  15.     public void onCreate()  
  16.         Log("service create");  
  17.      
  18.     @Override  
  19.     public void onStart(Intent intent, int startId)  
  20.         Log("service start id=" startId);  
  21.      
  22.       
  23.     @Override  
  24.     public IBinder onBind(Intent t)  
  25.         Log("service on bind");  
  26.         return mBinder;  
  27.      
  28.     @Override  
  29.     public void onDestroy()  
  30.         Log("service on destroy");  
  31.         super.onDestroy();  
  32.      
  33.     @Override  
  34.     public boolean onUnbind(Intent intent)  
  35.         Log("service on unbind");  
  36.         return super.onUnbind(intent);  
  37.      
  38.     public void onRebind(Intent intent)  
  39.         Log("service on rebind");  
  40.         super.onRebind(intent);  
  41.      
  42.     private final forService.Stub mBinder new forService.Stub()  
  43.         @Override  
  44.         public void invokCallBack() throws RemoteException  
  45.          
  46.             callback.performAction();  
  47.               
  48.          
  49.         @Override  
  50.         public void registerTestCall(forActivity cb) throws RemoteException  
  51.          
  52.             callback cb;  
  53.               
  54.          
  55.           
  56.     };  
  57.  

注意onBind(),它的返回类型为IBinder,返回了一个mBinder,看看mBinder的定义:

    private final forService.Stub mBinder = new forService.Stub() {

        @Override
        public void invokCallBack() throws RemoteException
        {
            callback.performAction();
         }

        @Override
        public void registerTestCall(forActivity cb) throws RemoteException
        {
            callback = cb;

        }

       };

它是实现了我们在AIDL中定义的方法,这个mBinder最终返回给了mAIDLActivity中的mService,于是在mAIDLActivity中可以使用mBinder中的方法了。在mAIDLActivity中也有一个类似mBinder的对象,看看定义:   

        private forActivity mCallback = new forActivity.Stub()

    {
        public void performAction() throws RemoteException
        {
            Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();
        }
      };

我们要在界面上显示一个toast,就是在这里实现的。这个对象,在mConnection的onServiceConnected()被调用时,通过调用mService(也就是远程的mAIDLService中的mBinder)的registerTestCall(),传递给了mAIDLService,于是在mAIDLService中可以调用performAction()了。

做一个大致总结,我们使用AIDL是要做什么呢:

让Acticity(或者说一个进程/一个类?)和Service(或者说远端进程/远端类/对象?)获取对方的一个Stub对象,这个对象在定义时实现了我们在AIDL中定义的方法,于是这些远程对象中的方法可以在本地使用了。如果这种使用(通信)是单向的,比如只是Activity需要通知Service做什么,那么只要Service中有一个Stub对象,并且传给Acticity就够了。

至于如何获得远程的Stub,参看上面的代码,看mConnection、registerTestCall、onRebind,它们展示了一种方法。

另外,有时候我们可能在一个类中有多个Stub对象,它们都要给远程交互的类的实例,这个时候可以考虑使用RemoteCallbackList<>(docs/reference/android/os/RemoteCallbackList.html)。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:25333次
    • 积分:213
    • 等级:
    • 排名:千里之外
    • 原创:95篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档