Service(下)之aidl绑定


在上一篇中,最后我们为了安全,隐藏了中间人,只是暴露了一个接口。
那么今天我们来说说aidl远程绑定Service这回事。没看过上一篇的请先移步我上一篇 Service绑定(上)

定义接口

其实很简单,我们只要把上一篇的IMiddlePerson这个接口文件后缀名改成aidl就可以了。

IMiddlePerson.java -> IMiddlePerson.aidl

改成这样后,系统会帮我们在build目录下(studio是build目录,eclipse是gen目录下)自动生成一个IMiddlePerson.java文件,这个文件如下:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * 
 */
package com.zyp.testservice.service;
/**
 * Created by ZYP on 2017/3/26 0026.
 */
public interface IMiddlePerson extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.zyp.testservice.service.IMiddlePerson
{
private static final java.lang.String DESCRIPTOR = "com.zyp.testservice.service.IMiddlePerson";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.zyp.testservice.service.IMiddlePerson interface,
 * generating a proxy if needed.
 */
public static com.zyp.testservice.service.IMiddlePerson asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.zyp.testservice.service.IMiddlePerson))) {
return ((com.zyp.testservice.service.IMiddlePerson)iin);
}
return new com.zyp.testservice.service.IMiddlePerson.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_handleThings:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.handleThings(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.zyp.testservice.service.IMiddlePerson
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void handleThings(int money) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
mRemote.transact(Stub.TRANSACTION_handleThings, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_handleThings = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void handleThings(int money) throws android.os.RemoteException;
}

这乱七八糟的一堆是什么东西?没事我们看主要的东西:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 *  */
public interface IMiddlePerson extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.zyp.testservice.service.IMiddlePerson
    {
        /**
         * Cast an IBinder object into an com.zyp.testservice.service.IMiddlePerson interface,
         * generating a proxy if needed.
         */
        public static com.zyp.testservice.service.IMiddlePerson asInterface(android.os.IBinder obj)
        {}
    }

    public void handleThings(int money) throws android.os.RemoteException;
}

看以上简略代码,看首行注释,那是studio自动生成的,告诉我们“DO NOT MODIFY”。
然后我们看到这个自动生成的IMiddlePerson.java类主要就是生成了一个内部类,继承Binder接口,并实现了我们定义的IMiddlePerson接口;而且handleThings()方法也是有的。
asInterface()方法看注释即可明白,他把一个IBinder对象强制转成一个我们对应包下的IMiddlePerson对象。

好了,我们该要的准备工作都已经完成。接下来我们建个项目试试;

建立远程项目Service

现在我们先建立一个RemoteService项目,

如上图,MainActivity里什么都没有,一个IMiddlePerson的aidl接口,一个RemoteService,
Service代码如下:

public class RemoteService extends Service {
    @Override
    public void onCreate() {
        Log.e(RemoteService.class.getSimpleName(),"服务被创建了");
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(RemoteService.class.getSimpleName(),"服务启动了");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        Log.e(RemoteService.class.getSimpleName(),"服务被销毁了");
        super.onDestroy();
    }
    private class MiddlePerson extends IMiddlePerson.Stub {
        @Override
        public void handleThings(int money) {
            if(money > 200){
                callLingDao();//请求领导办事
            }else{
                Toast.makeText(getApplicationContext(),"多准备点钱吧",Toast.LENGTH_SHORT).show();
            }
        }
        public void playMajiang(){
        }
    }
    public void callLingDao(){
        Log.e(RemoteService.class.getSimpleName(),"项目帮你批好了!");
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new MiddlePerson();
    }
}

IMiddlePerson.aidl接口:

interface IMiddlePerson {
    void handleThings(int money);
}

建立本地项目

我们再建立一个本地项目
这里写图片描述

然后把远程项目RemoteService里面的aidl文件连同完整的包路径都复制到这个项目,
本地的aidl文件要和远程的aidl文件所在文件路径都要完全一致,这样最后在ServiceConnection中强转IBinder类型到IMiddlePerson接口类时候才不会报错。

在本地项目中写入绑定远程服务的代码:

public void bindRemoteService(){
        //这里要用到隐示启动了
        Intent intent = new Intent("com.test.remoteservice");
        ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e(TAG,"bind succeed");
                //
                IMiddlePerson mp = IMiddlePerson.Stub.asInterface(service);
                //调用中间人的方法
                try {
                    mp.handleThings(500);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e(TAG,"Disconnected");
            }
        };
        bindService(intent,conn,BIND_AUTO_CREATE);
}

至此我们运行远端项目,然后运行本地项目,接着绑定远端Service,流程基本通了。

总结

aidl:android interface definetion language 安卓接口定义语言
aidl语言是没有访问修饰符的。
aidl都是公有的

流程:

1、在服务创建一个内部类,继承Binder,提供方法,访问服务内部的方法;
2、把暴露的接口文件文件的扩展名改成aidl文件,去掉访问修饰符public
(该接口文件用于定义服务的内部类里面的方法。)
private class MyBinder extends IMyBinder.Stub{} IPC的子类
3、实现服务的onBind()方法,返回MyBinder;
4、在antivity中绑定服务,bindService();
5、在服务成功绑定时候,会执行一个方法onServiceConnected(),传递过来一个IBinder对象;
6、IMyBinder.Stub.adInterface(binder)调用接口里面的方法,强转成你定义的接口。

猜你喜欢

转载自blog.csdn.net/zzzypp/article/details/66969556