三十一、跨进程调用Service(AIDL服务)

AIDL服务简介

Android的远程Service调用与Java的RMI基本相似,一样都是先定义一个远程调用接口,然后为该接口提供一个实现类即可。

与RIM不同的是,客户端访问Service时,Android并不是直接返回Service对象给客户端——这一点绑定本地Service时已经看到,Service只是将一个回调对象(IBinder对象)通过onBind()方法返回给客户端。因此Android的AIDL远程接口的实现类就是那个IBinder实现类。

与绑定本地Service不同的是,本地Service的onBind()方法会直接把IBinder对象本身传给客户端的ServiceConnention的onServiceConnected方法的第二个参数。但远程Service的onBind()方法只是将IBinder对象的代理传给客户端的ServiceConnection的onServiceConnected方法的第二个参数。

当客户端获取了远程Service的IBinder对象的代理之后,接下来就通过该IBinder对象去调用远程Service的属性或方法了。

创建AIDL文件

AIDL的语法与Java接口很相似,但存在如下差异:

1.AIDL定义接口的源代码必须以.aidl结尾
2.AIDL接口中用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其他类型全部都需要导包,即使他们在同一个包中也需要导包。

开发人员定义的AIDL接口只是定义了进程之间的通信接口,Service端、客户端都需要使用Android SDK安装目录下的platform-tools子目录下的aidl.exe工具为该接口提供实现。如果开发者使用ADT工具进行开发,那么ADT工具会自动为该AIDL接口生成实现。

Android Studio直接右键--new--AIDL--AIDL File

package com.hello.myandroidtest.service;

interface ICat {

    String getColor();

    double getWeight();
}

定义好上面的接口后,ADT工具会自动生成一个ICat.Java接口,在该接口里包含一个Stub内部类,该内部类实现了IBinder、ICat两个接口,这个Stub类将会作为远程Service的回调类——它实现了IBinder接口,因此可作为Service的onBinder()方法返回值。

将接口暴露给客户端

上一步定义好AIDL接口之后,接下来就可定义一个Service实现类了,该Service的onBind()方法所返回的IBinder对象应该是应该是ADT所生成的ICat.Stub的子类的实例。至于其他部分,则与开发本地Service完全一样。

public class AidlService extends Service {

    private CatBinder catBinder;

    Timer timer = new Timer();

    String[] colors = new String[]{
        "红色",
        "黄色",
        "黑色"
    };

    double[] weights = new double[]{
         2.3,
         3.1,
         1.58
    };

    private String color;

    private double weight;

    //继承Stub,也就是实现了ICat接口,并实现了IBinder接口
    public class CatBinder extends ICat.Stub{

        @Override
        public String getColor() throws RemoteException {
            return color;
        }

        @Override
        public double getWeight() throws RemoteException {
            return weight;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        catBinder = new CatBinder();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                //随机地改变Service组件内color、weight属性值
                int rand = (int) (Math.random() * 3);
                color = colors[rand];
                weight = weights[rand];
                System.out.println("------" + rand);
            }
        }, 0, 800);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        /* 
         * 返回catBinder对象
         * 
         * 在绑定本地Service的情况下,该catBinder对象会直接
         * 传给客户端的ServiceConnection
         * 的onServiceConnected方法的第二个参数
         * 
         * 在绑定远程Service的情况下,只将catBinder对象的代理
         * 传给客户端的ServiceConnection对象
         * 的onServiceConnected方法的第二个参数
         */
        return catBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        timer.cancel();
    }
}

清单配置文件


     
           
     

客户端访问AIDLService
public class Activity27 extends BaseActivity {

    private ICat catService;
    
    Button get;
    
    TextView color, weight;
    
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //获取远程Service的onBind方法返回的对象的代理
            catService = ICat.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            catService = null;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity27);
        get = findViewById(R.id.get);
        color = findViewById(R.id.color);
        weight = findViewById(R.id.weight);
        /*
         * 服务意图必须是显性声明。 这是为了防止造成冲突(有多个Service用同样的intent-filter的情况)
         * 这是Android 5.0 (Lollipop) 之后的规定。不能用包名的方式定义Service Intent, 而要用显
         * 性声明:new Intent(context, xxxService.class);
         *
         * 如果想继续使用隐式意图的话,加上包名信息即可
         */
        //创建绑定服务的Intent
        Intent intent = new Intent();
        intent.setAction("com.myandroid.service.AIDL_SERVICE");
        intent.setPackage(context.getPackageName());//兼容Android 5.0
        bindService(intent, conn, Service.BIND_AUTO_CREATE);
        get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try{
                    color.setText(catService.getColor());
                    weight.setText(String.valueOf(catService.getWeight()));
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.unbindService(conn);
    }
}

你可能感兴趣的:(三十一、跨进程调用Service(AIDL服务))