您的位置:首页 > 移动开发 > Android开发

Android AIDL远程调用

2014-06-20 11:11 218 查看
首先介绍一下AIDL

AIDL简介

      AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象.
我的理解它和java中的RMI的概念差不多,在这里我就不相信讲解什么事AIDL 了。既然AIDL是既然是可以在不同进程间(IPC)进行操作。

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

在Server客户端。

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

package com.lifeblood;

interface ITestService {

   int getAccountBalance();

   void setOwnerNames(in List<String> names);

   int getCustomerList(in String branch, out String[] customerList);

   void showTest();

}

复制代码

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

如下所示:

@Override

        public IBinder onBind(Intent intent) {

                // TODO Auto-generated method stub

                mContext = this;

                return binder;                //返回AIDL接口实例化对象

        }

复制代码
同时在该类中,实例化ITestService.stub字柄

//实现AIDL接口中各个方法

        private ITestService.Stub binder = new Stub(){

                private String name = null;

                public int getAccountBalance() throws RemoteException {

                        // TODO Auto-generated method stub

                        return 100000;

                }

                public int getCustomerList(String branch, String[] customerList)

                                throws RemoteException {

                        // TODO Auto-generated method stub

                        customerList[0] = name;

                        System.out.println("Name:"+branch);

                        return 0;

                }

                public void setOwnerNames(List<String> names) throws RemoteException {

                        // TODO Auto-generated method stub

                        name = names.get(0);

                        System.out.println("Size:"+names.size()+"=="+names.get(0));

                }

                public void showTest() throws RemoteException {

                        // TODO Auto-generated method stub

                        Intent intent = new Intent(mContext, AidlTtest.class);

                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

                        startActivity(intent);

                }

        };

复制代码
3.然后在Activity子类中进行测试,主要的工作就是开启上面实例化的Service子类

Intent service = new Intent(this, TestService.class);

startService(service);

复制代码

4.在AndroidManifest.xml注册该Service

<service android:name="TestService" android:process=":remote">

            <intent-filter>

                    <!-- AIDL完整路径名。必须指明,客户端能够通过AIDL类名查找到它的实现类 -->

                    <action android:name="com.lifeblood.ITestService" />

            </intent-filter>

        </service>

复制代码
(这样Server端的编码就结束了。然后就在Client类书写代码了。)

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

合适的地方。此步略。

6.最后在Client端的Acitivty中写入,如下代码:

//创建远程调用对象

        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;

                }

        };

................................

public void onClick(View v) {

                // TODO Auto-generated method stub

                int viewId = v.getId();

                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("李彬彬");

                                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();

                        }

                }catch(RemoteException e){

                        e.printStackTrace();

                }

...............................

@Override

        protected void onDestroy() {

                // TODO Auto-generated method stub

                super.onDestroy();

                

                unbindService(connection);

        }

复制代码

其中,

        //创建远程调用对象

        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,那么,只要当前的绑定对象都失去连接,就会停止服务 。

[align=left]这里回过头来说明一些android中的service[/align]
[align=left]Service概念及用途:[/align]
Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行,那 我们什么时候会用到Service呢?比如我们播放音乐的时候,有可能想边听音乐边干些其他事情,当我们退出播放音乐的应用,如果不用Service,我 们就听不到歌了,所以这时候就得用到Service了,又比如当我们一个应用的数据是通过网络获取的,不同时间(一段时间)的数据是不同的这时候我们可以
用Service在后台定时更新,而不用每打开应用的时候在去获取。
[align=left]Service生命周期 :[/align]
Android Service的生命周期并不像Activity那么复杂,它只继承了onCreate(),onStart(),onDestroy()三个方法,当我 们第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停止Service时,则执行onDestroy() 方法,这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行
onStart()方法,具体的可以看下面的实例。
[align=left]  (我是参考一个实例,如一个博客日志写的)[/align]
[align=left]下面我再举一个例子,这个例子是实现来电防火墙的功能,就是说,如果有指定的号码打入,电话会自动静音,并且会自动断开。[/align]
[align=left]由于Android1.1以上版本已经屏蔽了一些断开电话接入的API,而采取了AIDL方式。[/align]
[align=left]接下来讲解,我实现的过程和一些关键代码,如下所示:[/align]

  package com.android.internal.telephony;

interface ITelephony {

  boolean endCall();

  void answerRingingCall();

}

复制代码
为了显示所有细节,我将我写得所示关键代码写入:

package com.test.telephone;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import android.app.Activity;

import android.app.Service;

import android.content.Context;

import android.media.AudioManager;

import android.os.Bundle;

import android.os.RemoteException;

import android.telephony.PhoneStateListener;

import android.telephony.TelephonyManager;

import android.util.Log;

import android.widget.TextView;

import com.android.internal.telephony.ITelephony;

/***



* 参考:

* http://blog.csdn.net/chenzheng_java/archive/2011/03/20/6262578.aspx
* @author mingg

*

*/

public class ActivityMain extends Activity {

        private static final String TAG = "Telephony";

        TextView view = null;

        TelephonyManager mTelephonyMgr;

        private ITelephony iTelephony;

        @Override

        protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);

                 mTelephonyMgr = (TelephonyManager) this

                                .getSystemService(Context.TELEPHONY_SERVICE);

                

                mTelephonyMgr.listen(new TeleListener(),

                                PhoneStateListener.LISTEN_CALL_STATE);

                

                view = new TextView(this);

                view.setText("listen the state of phone\n");

                

                setContentView(view);

        }

        class TeleListener extends PhoneStateListener {

                @Override

                public void onCallStateChanged(int state, String incomingNumber) {

                        super.onCallStateChanged(state, incomingNumber);

                        switch (state) {

                        case TelephonyManager.CALL_STATE_IDLE: { //待机状态

                                Log.e(TAG, "CALL_STATE_IDLE");

                                view.append("CALL_STATE_IDLE " + "\n");

                                

                                //待机状态响铃正常

                                AudioManager  audioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);

                                if(audioManager!=null){

                                        /**设置响铃正常**、

                                         * 

                                         */

                                        audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);

                                        audioManager.getStreamVolume(AudioManager.STREAM_RING);//设置音量

                                        

                                        

                                }

                                

                                break;

                        }

                        case TelephonyManager.CALL_STATE_OFFHOOK: {//电话被挂起了

                                Log.e(TAG, "CALL_STATE_OFFHOOK");

                                view.append("CALL_STATE_OFFHOOK" + "\n");

                                break;

                        }

                        case TelephonyManager.CALL_STATE_RINGING: { //来电

                                

                                /**有电话接入**、

                                 * 

                                 */

                                

                                if(incomingNumber.equals("15915780893")){//黑名单电话号码

                                        AudioManager audioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);

                                        if(audioManager!=null){

                                                /**设置为静音模式**/

                                                audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);

                                           //也可以改为震动模式

//                                                audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);//

                                                audioManager.setRingerMode(AudioManager.STREAM_RING);

                                                

                                        }

                                        getTelephony();

                                        //初始化iTelephony

                                        try {

                                                iTelephony.endCall();

                                        } catch (RemoteException e) {

                                                // TODO Auto-generated catch block

                                                e.printStackTrace();

                                        } 

                                }

                                

                                Log.e(TAG, "CALL_STATE_RINGING");

                                view.append("CALL_STATE_RINGING" +incomingNumber+ "\n");

                                break;

                        }

                        default:

                                break;

                        }

                }

        }

        

        

        public void getTelephony()

            {

              TelephonyManager telMgr = 

                     (TelephonyManager)getSystemService(Service.TELEPHONY_SERVICE); 

              

              Class <TelephonyManager> c = TelephonyManager.class;

               Method getITelephonyMethod = null;

                try {

                      getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[])null);

                      getITelephonyMethod.setAccessible(true);

                } catch (SecurityException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

                } catch (NoSuchMethodException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

                }

                try {

                iTelephony = (ITelephony) getITelephonyMethod.invoke(telMgr, (Object[])null);

                } catch (IllegalArgumentException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

                } catch (IllegalAccessException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

                } catch (InvocationTargetException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

                }

            }

}

复制代码

代码分析: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进行权限申请:

<uses-permission android:name="android.permission.READ_PHONE_STATE" /> 

    <uses-permission android:name="android.permission.VIBRATE" /> 

    <uses-permission android:name="android.permission.CALL_PHONE" />

复制代码
http://www.apkbus.com/forum.php?mod=viewthread&tid=142
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: