Android开发之AIDL

举报
yd_221104950 发表于 2020/12/03 23:15:17 2020/12/03
【摘要】 概述 在Android中实现跨进程通信的方式有很多种,如广播、Content Provider、AIDL(Android Interface Definition Language)。AIDL在跨进程通信中用得最多,因为AIDL相比其他方式,速度更快,效率更高。 AIDL最常见的使用场景:让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用...

概述

在Android中实现跨进程通信的方式有很多种,如广播、Content Provider、AIDL(Android Interface Definition Language)。AIDL在跨进程通信中用得最多,因为AIDL相比其他方式,速度更快,效率更高。

AIDL最常见的使用场景:让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。

接下来我们创建一个服务端和一个客户端,说明客户端如何从服务端获取数据。首先,我们先把客户端和服务端的项目目录建出来:
在这里插入图片描述

服务端

1、IMyAidlInterface.aidl文件

右键项目remoteservice->New->AIDL->AIDL File

  
 
  • 1

创建好后的目录:
在这里插入图片描述

// IMyAidlInterface.aidl
package com.wong.remoteservice;
// Declare any non-default types here with import statements
interface IMyAidlInterface { // 服务端数据 String getString();
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

创建完aidl文件以后,build一下项目,然后会在remoteservice/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out/下会生成一个aidl文件,那说明AIDL文件已经编译成功,如:
在这里插入图片描述编译好后的IMyAidlInterface.java,是这样的:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.wong.remoteservice;
// Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface
{
  /** Default implementation for IMyAidlInterface. */
  public static class Default implements com.wong.remoteservice.IMyAidlInterface
  { // 服务端数据 @Override public java.lang.String getString() throws android.os.RemoteException { return null; } @Override public android.os.IBinder asBinder() { return null; }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.wong.remoteservice.IMyAidlInterface
  { private static final java.lang.String DESCRIPTOR = "com.wong.remoteservice.IMyAidlInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.wong.remoteservice.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.wong.remoteservice.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.wong.remoteservice.IMyAidlInterface))) { return ((com.wong.remoteservice.IMyAidlInterface)iin); } return new com.wong.remoteservice.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 { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_getString: { data.enforceInterface(descriptor); java.lang.String _result = this.getString(); reply.writeNoException(); reply.writeString(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.wong.remoteservice.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 java.lang.String getString() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_getString, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getString(); } _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.wong.remoteservice.IMyAidlInterface sDefaultImpl; } static final int TRANSACTION_getString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static boolean setDefaultImpl(com.wong.remoteservice.IMyAidlInterface impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.wong.remoteservice.IMyAidlInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; }
  }
  // 服务端数据 public java.lang.String getString() throws android.os.RemoteException;
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

是的,你没有看错,在这个编译好的IMyAidlInterface.java文件,除了最后一个getString()方法是我们自己写的以外,其他都是在编译时加上的,而且这个才是我们以后要用的。 从上面可以看到较未编译之前多了以下这些:

  • IMyAidlInterface接口继承了接口android.os.IInterface;
  • 一个实现了IMyAidlInterface接口的静态类Default;
  • 本地端IPC的实现类Stub(里面还有个Proxy代理类),不过它是个抽象类,需要本地实现它;
    在这里插入图片描述
    2、创建一个MyService类
package com.wong.remoteservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import androidx.annotation.Nullable;

public class MyService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return new MyBind(); } class MyBind extends IMyAidlInterface.Stub{ @Override public String getString() throws RemoteException { return "服务端:Hello world"; } }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

本地服务内部类继承的是Binder,而现在继承的是IMyAidlInterface.Stub,就是我们刚刚建立的aidl文件。
AndroidManifest.xml配置:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.wong.remoteservice"> <application> <service android:name=".MyService"> <intent-filter> <action android:name="android.intent.action.com.wong.remoteservice.MY_SERVICE" /> </intent-filter> </service> </application>
</manifest>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

remoteservice项目的build.gradle构建脚本,配置成以组件来构建,而不插件:

// 而不是apply plugin: 'com.android.library'
apply plugin: 'com.android.application'

android {
	... defaultConfig { applicationId "com.wong.remoteservice" ... }
	...
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3、以无界面无图标运行remoteservice App
在这里插入图片描述像上面这样选择app后,就可以以无图标无界面只提供MyService的app运行在手机上了。

客户端

1、首先将在服务端创建的IMyAidlInterface.aidl原封不动的复制到客户端来(注意:路径要一模一样)。复制后在客户端的目录:
在这里插入图片描述build一下项目后,也会得到编译好的IMyAidlInterface.java文件,路径和在服务端是一样的,如:
在这里插入图片描述
2、我们在客户諯调用服务端的服务MyService
(1)因为我们要服务返回数据,所以需要使用到bindService这种方式,那么我们要先定义ServiceConnection:

 	private IMyAidlInterface myBind; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { myBind = IMyAidlInterface.Stub.asInterface(service); try { mTvData.setText(myBind.getString()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { myBind = null; } };

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

(2)调用服务端的服务

Intent intent = new Intent();
/*从 Android 5.0开始 隐式Intent绑定服务的方式已不能使用,所以这里需要设置Service所在服务端的包名*/
intent.setPackage("com.wong.remoteservice");
intent.setAction("android.intent.action.com.wong.remoteservice.MY_SERVICE");
bindService(intent,serviceConnection,BIND_AUTO_CREATE);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

(3)运行客户端代码就可以调用到刚刚安装上的服务了。

连接本地服务和连接远程服务的代码是一样的,只是调用远程服务的是用到了AIDL技术。

以下是两个demo可以下载来运行试试。

远程服务:demo
本地服务:demo

谢谢阅读

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/103854756

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。