Android开发之AIDL
概述
在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可以下载来运行试试。
谢谢阅读
文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/weixin_40763897/article/details/103854756
- 点赞
- 收藏
- 关注作者
评论(0)