Android AIDL远程调用

来源:互联网 发布:虚拟midi键盘软件 编辑:程序博客网 时间:2024/05/29 10:58
首先介绍一下AIDL
AIDL简介
      AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象.
我的理解它和java中的RMI的概念差不多,在这里我就不相信讲解什么事AIDL 了。既然AIDL是既然是可以在不同进程间(IPC)进行操作。

下面我来通过一个简单的两个项目实例来讲解,一个是Server,一个是Client.

在Server客户端。

1.创建一个文件ITestService.aidl,如下所示:
  1. package com.lifeblood;

  2. interface ITestService {
  3.    int getAccountBalance();
  4.    void setOwnerNames(in List<String> names);
  5.    int getCustomerList(in String branch, out String[] customerList);
  6.    void showTest();
  7. }
复制代码

2.创建TestService.java类,该类继承Service类,实现public IBinder onBind(Intent intent)方法,

如下所示:
  1. @Override
  2.         public IBinder onBind(Intent intent) {
  3.                 // TODO Auto-generated method stub
  4.                 mContext = this;
  5.                 return binder;                //返回AIDL接口实例化对象
  6.         }
复制代码
同时在该类中,实例化ITestService.stub字柄
  1. //实现AIDL接口中各个方法
  2.         private ITestService.Stub binder = new Stub(){
  3.                 private String name = null;
  4.                 public int getAccountBalance() throws RemoteException {
  5.                         // TODO Auto-generated method stub
  6.                         return 100000;
  7.                 }

  8.                 public int getCustomerList(String branch, String[] customerList)
  9.                                 throws RemoteException {
  10.                         // TODO Auto-generated method stub
  11.                         customerList[0] = name;
  12.                         System.out.println("Name:"+branch);
  13.                         return 0;
  14.                 }

  15.                 public void setOwnerNames(List<String> names) throws RemoteException {
  16.                         // TODO Auto-generated method stub
  17.                         name = names.get(0);
  18.                         System.out.println("Size:"+names.size()+"=="+names.get(0));
  19.                 }

  20.                 public void showTest() throws RemoteException {
  21.                         // TODO Auto-generated method stub
  22.                         Intent intent = new Intent(mContext, AidlTtest.class);
  23.                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  24.                         startActivity(intent);
  25.                 }
  26.         };
复制代码
3.然后在Activity子类中进行测试,主要的工作就是开启上面实例化的Service子类
  1. Intent service = new Intent(this, TestService.class);
  2. startService(service);
复制代码

4.在AndroidManifest.xml注册该Service
  1. <service android:name="TestService" android:process=":remote">
  2.             <intent-filter>
  3.                     <!-- AIDL完整路径名。必须指明,客户端能够通过AIDL类名查找到它的实现类 -->
  4.                     <action android:name="com.lifeblood.ITestService" />
  5.             </intent-filter>
  6.         </service>
复制代码
(这样Server端的编码就结束了。然后就在Client类书写代码了。)

5.其实Aidl远程就相当于JAVA RMI 远程调用,也就是说也要在客户端书写一样的AIDL源文件。而且package包没有限制。可以写在任何你认为

合适的地方。此步略。


6.最后在Client端的Acitivty中写入,如下代码:
  1. //创建远程调用对象
  2.         private ServiceConnection connection = new ServiceConnection(){

  3.                 public void onServiceConnected(ComponentName name, IBinder service) {
  4.                         // TODO Auto-generated method stub
  5.                         //从远程service中获得AIDL实例化对象
  6.                         tService = ITestService.Stub.asInterface(service);
  7.                         System.out.println("Bind Success:"+tService);
  8.                 }

  9.                 public void onServiceDisconnected(ComponentName name) {
  10.                         // TODO Auto-generated method stub
  11.                         tService = null;
  12.                 }
  13.         };

  14. ................................
  15. public void onClick(View v) {
  16.                 // TODO Auto-generated method stub
  17.                 int viewId = v.getId();
  18.                 try{
  19.                         if (viewId == btn.getId()){
  20.                                 
  21.                                 Intent service = new Intent(ITestService.class.getName());
  22.                                 
  23.                                 //ITestService.class.getName()
  24.                                 
  25.                                 //绑定AIDL
  26.                                 bindService(service, connection, BIND_AUTO_CREATE);
  27.                         }else if (viewId == btn1.getId()){
  28.                                 text.setText("远程结果:"+tService.getAccountBalance());
  29.                         }else if (viewId == btn2.getId()){
  30.                                 List<String> names = new ArrayList<String>();
  31.                                 names.add("李彬彬");
  32.                                 tService.setOwnerNames(names);
  33.                         }else if (viewId == btn3.getId()){
  34.                                 String[] customerList = new String[1];
  35.                                 tService.getCustomerList("向华", customerList);
  36.                                 text.setText("远程结果:"+customerList[0]);
  37.                         }else if (viewId == btn4.getId()){
  38.                                 tService.showTest();
  39.                         }
  40.                 }catch(RemoteException e){
  41.                         e.printStackTrace();
  42.                 }

  43. ...............................

  44. @Override
  45.         protected void onDestroy() {
  46.                 // TODO Auto-generated method stub
  47.                 super.onDestroy();
  48.                 
  49.                 unbindService(connection);
  50.         }
复制代码

其中,

        //创建远程调用对象

        private ServiceConnection connection = new ServiceConnection(){
                public void onServiceConnected(ComponentName name, IBinder service) {
                        // TODO Auto-generated method stub
                        //从远程service中获得AIDL实例化对象

                        tService = ITestService.Stub.asInterface(service);

                       System.out.println("Bind Success:"+tService);
                }

                public void onServiceDisconnected(ComponentName name) {

                        // TODO Auto-generated method stub

                        tService = null;

                }

        };


    用于实例化该        private ITestService tService = null变量。 这样就可以通过点击事件来启动该服务中的方法.



try{


                        if (viewId == btn.getId()){

                                Intent service = new Intent(ITestService.class.getName());


                               //ITestService.class.getName()

                                //绑定AIDL


                                bindService(service, connection, BIND_AUTO_CREATE);


                        }else if (viewId == btn1.getId()){

                                text.setText("远程结果:"+tService.getAccountBalance());


                        }else if (viewId == btn2.getId()){


                                List<String> names = new ArrayList<String>();

                                names.add("mingg");

                                tService.setOwnerNames(names);

                        }else if (viewId == btn3.getId()){

                                String[] customerList = new String[1];

                                tService.getCustomerList("向华", customerList);

                                text.setText("远程结果:"+customerList[0]);


                        }else if (viewId == btn4.getId()){


                                tService.showTest();

                        }


        如果要退出程序,不要忘了在onDestroy方法中加入

@Override

        protected void onDestroy() {


                // TODO Auto-generated method stub

                super.onDestroy();

                unbindService(connection);

        }

    要注意以下几点:
  • 使用getApplicationContext()所获取的上下文来绑定和解绑定服务,这个时候即使不用unbindService也是不会出错的。具体原因还未深究。
  • 如果不想用getApplicationContext(),那么就必须在结束Activity时运行解绑定操作。
  • 如果unbindService(conn)中的conn没有被绑定到服务端,将报java.lang.IllegalArgumentException: Service not registered这样的错误。证明了这个方法不宜调用第二次。
  • 当以startService的方式打开服务,即使当前服务没有绑定的对象也不会停止服务,除非stopService才能停止。反之如果先运行的是bindService,那么,只要当前的绑定对象都失去连接,就会停止服务 。

    这里回过头来说明一些android中的service
    Service概念及用途:
    Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行,那 我们什么时候会用到Service呢?比如我们播放音乐的时候,有可能想边听音乐边干些其他事情,当我们退出播放音乐的应用,如果不用Service,我 们就听不到歌了,所以这时候就得用到Service了,又比如当我们一个应用的数据是通过网络获取的,不同时间(一段时间)的数据是不同的这时候我们可以 用Service在后台定时更新,而不用每打开应用的时候在去获取。
    Service生命周期 :
    Android Service的生命周期并不像Activity那么复杂,它只继承了onCreate(),onStart(),onDestroy()三个方法,当我 们第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停止Service时,则执行onDestroy() 方法,这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行 onStart()方法,具体的可以看下面的实例。
  (我是参考一个实例,如一个博客日志写的)
下面我再举一个例子,这个例子是实现来电防火墙的功能,就是说,如果有指定的号码打入,电话会自动静音,并且会自动断开。
由于Android1.1以上版本已经屏蔽了一些断开电话接入的API,而采取了AIDL方式。
接下来讲解,我实现的过程和一些关键代码,如下所示:
  1.   package com.android.internal.telephony;
  2. interface ITelephony {
  3.   boolean endCall();
  4.   void answerRingingCall();
  5. }
复制代码
为了显示所有细节,我将我写得所示关键代码写入:
  1. package com.test.telephone;
  2. import java.lang.reflect.InvocationTargetException;
  3. import java.lang.reflect.Method;
  4. import android.app.Activity;
  5. import android.app.Service;
  6. import android.content.Context;
  7. import android.media.AudioManager;
  8. import android.os.Bundle;
  9. import android.os.RemoteException;
  10. import android.telephony.PhoneStateListener;
  11. import android.telephony.TelephonyManager;
  12. import android.util.Log;
  13. import android.widget.TextView;
  14. import com.android.internal.telephony.ITelephony;
  15. /***

  16. * 参考:
  17. * http://blog.csdn.net/chenzheng_java/archive/2011/03/20/6262578.aspx
  18. * @author mingg
  19. *
  20. */
  21. public class ActivityMain extends Activity {
  22.         private static final String TAG = "Telephony";
  23.         TextView view = null;
  24.         TelephonyManager mTelephonyMgr;
  25.         private ITelephony iTelephony;
  26.         @Override
  27.         protected void onCreate(Bundle savedInstanceState) {
  28.                 super.onCreate(savedInstanceState);
  29.                  mTelephonyMgr = (TelephonyManager) this
  30.                                 .getSystemService(Context.TELEPHONY_SERVICE);
  31.                 
  32.                 mTelephonyMgr.listen(new TeleListener(),
  33.                                 PhoneStateListener.LISTEN_CALL_STATE);
  34.                 
  35.                 view = new TextView(this);
  36.                 view.setText("listen the state of phone\n");
  37.                 
  38.                 setContentView(view);
  39.         }
  40.         class TeleListener extends PhoneStateListener {
  41.                 @Override
  42.                 public void onCallStateChanged(int state, String incomingNumber) {
  43.                         super.onCallStateChanged(state, incomingNumber);
  44.                         switch (state) {
  45.                         case TelephonyManager.CALL_STATE_IDLE: { //待机状态
  46.                                 Log.e(TAG, "CALL_STATE_IDLE");
  47.                                 view.append("CALL_STATE_IDLE " + "\n");
  48.                                 
  49.                                 //待机状态响铃正常
  50.                                 AudioManager  audioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
  51.                                 if(audioManager!=null){
  52.                                         /**设置响铃正常**、
  53.                                          * 
  54.                                          */
  55.                                         audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
  56.                                         audioManager.getStreamVolume(AudioManager.STREAM_RING);//设置音量
  57.                                         
  58.                                         
  59.                                 }
  60.                                 
  61.                                 break;
  62.                         }
  63.                         case TelephonyManager.CALL_STATE_OFFHOOK: {//电话被挂起了
  64.                                 Log.e(TAG, "CALL_STATE_OFFHOOK");
  65.                                 view.append("CALL_STATE_OFFHOOK" + "\n");
  66.                                 break;
  67.                         }
  68.                         case TelephonyManager.CALL_STATE_RINGING: { //来电
  69.                                 
  70.                                 /**有电话接入**、
  71.                                  * 
  72.                                  */
  73.                                 
  74.                                 if(incomingNumber.equals("15915780893")){//黑名单电话号码
  75.                                         AudioManager audioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
  76.                                         if(audioManager!=null){
  77.                                                 /**设置为静音模式**/
  78.                                                 audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
  79.                                            //也可以改为震动模式
  80. //                                                audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);//
  81.                                                 audioManager.setRingerMode(AudioManager.STREAM_RING);
  82.                                                 
  83.                                         }
  84.                                         getTelephony();
  85.                                         //初始化iTelephony
  86.                                         try {
  87.                                                 iTelephony.endCall();
  88.                                         } catch (RemoteException e) {
  89.                                                 // TODO Auto-generated catch block
  90.                                                 e.printStackTrace();
  91.                                         } 
  92.                                 }
  93.                                 
  94.                                 Log.e(TAG, "CALL_STATE_RINGING");
  95.                                 view.append("CALL_STATE_RINGING" +incomingNumber+ "\n");
  96.                                 break;
  97.                         }
  98.                         default:
  99.                                 break;
  100.                         }
  101.                 }
  102.         }
  103.         
  104.         
  105.         public void getTelephony()
  106.             {
  107.               TelephonyManager telMgr = 
  108.                      (TelephonyManager)getSystemService(Service.TELEPHONY_SERVICE); 
  109.               
  110.               Class <TelephonyManager> c = TelephonyManager.class;
  111.                Method getITelephonyMethod = null;
  112.                 try {
  113.                       getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[])null);
  114.                       getITelephonyMethod.setAccessible(true);
  115.                 } catch (SecurityException e) {
  116.                 // TODO Auto-generated catch block
  117.                 e.printStackTrace();
  118.                 } catch (NoSuchMethodException e) {
  119.                 // TODO Auto-generated catch block
  120.                 e.printStackTrace();
  121.                 }
  122.                 try {
  123.                 iTelephony = (ITelephony) getITelephonyMethod.invoke(telMgr, (Object[])null);
  124.                 } catch (IllegalArgumentException e) {
  125.                 // TODO Auto-generated catch block
  126.                 e.printStackTrace();
  127.                 } catch (IllegalAccessException e) {
  128.                 // TODO Auto-generated catch block
  129.                 e.printStackTrace();
  130.                 } catch (InvocationTargetException e) {
  131.                 // TODO Auto-generated catch block
  132.                 e.printStackTrace();
  133.                 }
  134.             }
  135. }
复制代码

代码分析:TelephonyManager mTelephonyMgr;mTelephonyMgr = (TelephonyManager) this
                .getSystemService(Context.TELEPHONY_SERVICE);
        
        mTelephonyMgr.listen(new TeleListener(),
                PhoneStateListener.LISTEN_CALL_STATE);这个就是电话管理器,电话有三种状态,可以对其进行监听。class TeleListener extends PhoneStateListener {

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            switch (state) {
            case TelephonyManager.CALL_STATE_IDLE: { //待机状态
    
                
                break;
            }
            case TelephonyManager.CALL_STATE_OFFHOOK: {//电话被挂起了
          
            }
            case TelephonyManager.CALL_STATE_RINGING: { //来电
                
                /**有电话接入**、
                 * 
                 */

                break;
            }
            default:
                break;
            }
        }

    }

    这里我们来看来电时候的状态:TelephonyManager.CALL_STATE_RINGING     if(audioManager!=null){
                        /**设置为静音模式**/
                        audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
                       //也可以改为震动模式
//                        audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);//
                        audioManager.setRingerMode(AudioManager.STREAM_RING);
                        
                    }
                    getTelephony();
                    //初始化iTelephony
                        iTelephony.endCall();                      //挂断电话。这里我们没有使用Service子类实现,由于实现的功能简单,如果实现的逻辑比较复杂的话,我们一般希望加入Service,如第一个实例那样封装Aidl。注意:在getTelephony()方法中,我们使用JAVA反射机制。TelephonyManager telMgr = (TelephonyManager)getSystemService(Service.TELEPHONY_SERVICE); 
          
          Class <TelephonyManager> c = TelephonyManager.class;
           Method getITelephonyMethod = null;
         
              getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[])null);
               getITelephonyMethod.setAccessible(true);
      
            iTelephony = (ITelephony) getITelephonyMethod.invoke(telMgr, (Object[])null);关于JAVA的反射机制,我将会在后续再次提到。最后当然不要忘了在AndroidManifest.xml进行权限申请:
  1. <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
  2.     <uses-permission android:name="android.permission.VIBRATE" /> 
  3.     <uses-permission android:name="android.permission.CALL_PHONE" />
复制代码

http://www.apkbus.com/forum.php?mod=viewthread&tid=142
0 0
原创粉丝点击