android进阶3step2:Android App通信——AIDL实现远程服务的通信

安卓接口描述语言AIDL

全称:Android Interface definition language 

作用:进程间的通信接口(实现两个进程数据共享)

IBinder可以进行进程间和跨进程间的调用

定义转:https://www.jianshu.com/p/29999c1a93cd 

AIDL 意思即 Android Interface Definition Language,翻译过来就是Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码。从某种意义上说AIDL其实是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此而生成的一个IInterface的实例代码,AIDL其实是为了避免我们重复编写代码而出现的一个模板

设计AIDL这门语言的目的就是为了实现进程间通信。在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求

通常,暴露方法给其他应用进行调用的应用称为服务端,调用其他应用的方法的应用称为客户端,客户端通过绑定服务端的Service来进行交互

一、远程启动服务

ServiceDemo实现同一个进程间启动、停止、绑定、解绑服务等操作

依次点击

  1. 启动服务
  2. 绑定服务
  3. 解绑服务
  4. 停止服务
/com.demo.servicedemo D/MyService-vv: onCreate: 
/com.demo.servicedemo D/MyService-vv: onStartCommand: 
/com.demo.servicedemo D/MyService-vv: onBind: 
/com.demo.servicedemo D/MainActivity-vv: onServiceConnected: 
/com.demo.servicedemo D/MainActivity-vv: 当前进度是: 2
/com.demo.servicedemo D/MyService-vv: onUnbind: 
/com.demo.servicedemo D/MyService-vv: onDestroy: 

 MyService.java


import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * <p>文件描述:<p>
 * <p>作者:Mr-Donkey<p>
 * <p>创建时间:2018/11/25 14:03<p>
 * <p>更改时间:2018/11/25 14:03<p>
 * <p>版本号:1<p>
 */

/**
 * Service进行同一个进程的通信
 */
public class MyService extends Service {
    private static final String TAG = "MyService-vv";
    private int i;
    public static boolean IsBinder = false;

    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
        //开启一个线程(从1数到100),用于模拟耗时的任务
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    for (i = 1; i <= 100; i++) {
                        sleep(1000);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 绑定服务后会在on
     *
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        IsBinder = true;
        return new MyBinder();
    }

    /**
     * Binder是IBinder的空实现类
     * 提供一个方法用于获取当前计数的进度
     */
    public class MyBinder extends Binder {
        public int getProcess() {
            return i;
        }
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind: ");
        IsBinder = false;
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
    }
}

在AndroidManifest.xml中 注册Service

   android:exported="true" 表明当前Service对其他App开放

并且要设置action。

   <application
       ....
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.demo.myservice" />
            </intent-filter>
        </service>
    </application>

 MainActivity.java


import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity-vv";
    private MyService.MyBinder mb;
    private ServiceConnection conn = new ServiceConnection() {


        //当客户端正常连接着服务时,执行服务的绑定操作会被调用
        //此时传来的IBinder对象是onbinder的返回的对象
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: ");
            //将IBinder对象转成MyBinder
            mb = (MyService.MyBinder) service;
            //调用MyBinder中的获取进度的方法:实现监控
            int process = mb.getProcess();
            Log.d(TAG, "当前进度是: " + process);
        }

        //当客户端和服务的连接丢失了
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected: ");

        }
    };

    //IBinder
    //ServicerConnection:用于绑定客户端和Service
    //进度监控
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * 按钮点击事件
     *
     * @param v
     */
    public void operate(View v) {
        switch (v.getId()) {
            case R.id.start:
                //启动服务:创建-->启动-->销毁
                //如果服务已经创建了,后续重复启动,操作的都是同一个服务,不会再重新创建了,除非你先销毁它
                Intent it1 = new Intent(this, MyService.class);
                startService(it1);
                break;
            case R.id.stop:
                Intent it2 = new Intent(this, MyService.class);
                stopService(it2);
                break;
            case R.id.bind:
                //绑定服务:最大的 作用是用来实现对Service执行的任务进行进度监控
                //如果服务不存在: onCreate-->onBind-->onUnbind-->onDestory
                // (此时服务没有再后台运行,并且它会随着Activity的摧毁而解绑并销毁)
                //服务已经存在:那么bindService方法只能使onBind方法被调用,而unbindService方法只能使onUnbind被调用
                Intent it3 = new Intent(this, MyService.class);
                bindService(it3, conn, BIND_AUTO_CREATE);

                break;
            case R.id.unbind:
                //解绑服务
                if (MyService.IsBinder)
                    unbindService(conn);
                break;
        }
    }
}

新建一个AIDLDemo来远程启动服务

主要是通过显示声明Intent来操作另外一个Servicedemo app

确保Servicedemo的AndroidManifest.xml中配置写正确,还有两个app同时运行在手机上


import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * android5.0后要通过显式声明Intent来实现远程启动服务
     */
    public void operate(View view) {
        switch (view.getId()) {
            case R.id.start:
                Intent it1 = new Intent();
                it1.setAction("com.demo.myservice");
                it1.setPackage("com.demo.servicedemo");
                startService(it1);
                break;
            case R.id.stop:
                Intent it2 = new Intent();
                it2.setAction("com.demo.myservice");
                it2.setPackage("com.demo.servicedemo");
                stopService(it2);
                break;
            case R.id.bind:
                Intent it3 = new Intent();
                it3.setAction("com.demo.myservice");
                it3.setPackage("com.demo.servicedemo");
                bindService(it3, conn, BIND_AUTO_CREATE);
                break;
            case R.id.unbind:
                //解绑服务
                unbindService(conn);
                break;
        }
    }
}

这样一来就可以远程操作了。

二、远程服务通信

AIDL的使用

AIDL 作为进程之间通信的桥梁,使用 AIDL 需要遵守一些规则,包括数据的特定要求。

编写 AIDL 文件需要遵守如下语法规则:
1、 文件后缀名必须为.aidl;
2、 AIDL 默认支持的数据类型如下: byte,short,int,long,float,double,boolean,char,String,CharSequence, List,Map(List、Map 中定义的类型也需要是 AIDL 支持的)

3、 AIDL 也支持自定义实体类,但对实体类的操作是有要求的:

  • 1) 创建类 MyBean,需要实现 Parcelable 接口
  • 2) aidl 目录下创建相同包名的 MyBean.aidl 文件,并添加如下代 码:
package 包名; 
parcelable MyBean;
  • 3) 在其他 aidl 文件中,添加如下导包语句,引入 MyBean 类:
import 包名.MyBean;

下面是默认支持数据类型的实现: 

通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求

  1. 创建AIDL文件
  2. 自动生成AIDL的java文件
  3. 使用AIDL

在servicedemo中

一、创建AIDL文件

main文件夹右键New——>AIDL——>AIDL File

然后就在main文件夹下生成一个aidl文件夹这个文件夹中又有一个和java中的包名一致的包,里面生成自定义的.aidl文件 

IMyAidlInterface.aidl 里面的内容

可以看见其实一个接口,可以写你想要实现的接口方法,以下是默认的,那么我添加一个获取进度的方法getProcess()

// IMyAidlInterface.aidl
package com.demo.servicedemo;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

添加方法后(去不去掉默认的方法都可以)  我这里去掉了

// IMyAidlInterface.aidl
package com.demo.servicedemo;

// Declare any non-default types here with import statements

interface IMyAidlInterface {

   void getProcess();
}

2.自动生成AIDL的java文件

Builde——>Rebuild Project 就可以自动生成aidl的java文件了

位于:build——>generated——>source——>aidl——>debug下

这是自动生成的aidl的java文件,不用看得懂,其实就是实现进程间通信的具体实现

注意:

public static abstract class Stub extends android.os.Binder implements com.demo.servicedemo.IMyAidlInterface

1.其实Stub抽象类是继承了Binder(是IBinder的一个空实现类),那么Stub也是IBinder的子类

就可以在 服务绑定的时候,返回这个Stub对象来替换之前的MyBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        IsBinder = true;
        return new MyBinder();
    }

  /**
     * Binder是IBinder的空实现类
     * 提供一个方法用于获取当前计数的进度
     */
    public class MyBinder extends Binder {
        public int getProcess() {
            return i;
        }
    }
修改后的onBind 
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        IsBinder = true;
        return new IMyAidlInterface.Stub() {
            @Override
            public void getProcess() throws RemoteException {
                Log.d(TAG, "getProcess: " + i);
            }
        };
    }

返回一个Stub对象

2.public static com.demo.servicedemo.IMyAidlInterface asInterface(android.os.IBinder obj)

asInterface是Stub特别重要的一个方法

可以通过传入Stub对象来获取com.demo.servicedemo.IMyAidlInterface的实例,进而调用在com.demo.servicedemo.IMyAidlInterface自定义的方法来获取数据

在绑定服务成功后,onServiceConnected中收到onBind()返回的IBinder对象

此时可以通过

   IMyAidlInterface im = IMyAidlInterface.Stub.asInterface(service);
                //获取自定义方法 
               im.getProcess();

来获取当前进度

完整代码: 

   private ServiceConnection conn = new ServiceConnection() {


        //当客户端正常连接着服务时,执行服务的绑定操作会被调用
        //此时传来的IBinder对象是onbinder的返回的对象
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: ");
            try {
                //拿到IMyAidlInterface对象实例
               IMyAidlInterface im = IMyAidlInterface.Stub.asInterface(service);
                //获取自定义方法 
               im.getProcess();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        //当客户端和服务的连接丢失了
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected: ");

        }

 

 IMyAidlInterface.java

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/mac/Downloads/Android3Step1/servicedemo/src/main/aidl/com/demo/servicedemo/IMyAidlInterface.aidl
 */
package com.demo.servicedemo;
// Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.demo.servicedemo.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.demo.servicedemo.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.demo.servicedemo.IMyAidlInterface interface,
 * generating a proxy if needed.
 */
public static com.demo.servicedemo.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.demo.servicedemo.IMyAidlInterface))) {
return ((com.demo.servicedemo.IMyAidlInterface)iin);
}
return new com.demo.servicedemo.IMyAidlInterface.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_getProcess:
{
data.enforceInterface(DESCRIPTOR);
this.getProcess();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.demo.servicedemo.IMyAidlInterface
{
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 getProcess() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getProcess, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getProcess = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void getProcess() throws android.os.RemoteException;
}

 在AIDLDemo中

  1. 同样创建一样的aidl文件
  2. 生成aidl的java文件
  3. 使用aidl

copy main文件夹下的aidl文件夹,然后rebuild project生成java文件

这样是保持aidl的匹配一致

那么在AIDLDemo中的MainActivity中就可以获取到servicedemo中的进度值了

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                IMyAidlInterface im = IMyAidlInterface.Stub.asInterface(service);
                im.getProcess();
                Log.d(TAG, "onServiceConnected: AIDLDemo拿到进度值");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

在AIDLDemo中依次进行启动、绑定、解绑、停止服务的log 

servicedemo的log 

/com.demo.servicedemo D/MyService-vv: onCreate: 
/com.demo.servicedemo D/MyService-vv: onStartCommand: 
/com.demo.servicedemo D/MyService-vv: onBind: 
/com.demo.servicedemo D/MyService-vv: getProcess: 2
/com.demo.servicedemo D/MyService-vv: onUnbind: 
/com.demo.servicedemo D/MyService-vv: onDestroy: 

 AIDLDemo的log

/com.demo.android3step2 D/MainActivity-vv: onServiceConnected: AIDLDemo拿到进度值

进行进程间对象的传递也是一样的性质:

更多内容参考:

Android AIDL使用详解 

Android跨进程通信:图文详解 Binder机制 原理

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值