文章目录
前言
Android IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程间进行数据交换的过程
。本文介绍的aidl就是一种IPC方式。contentprovider也是一种IPC方式。
ContentProvider的使用方式
提示:以下是本篇文章正文内容,下面案例可供参考
一、AIDL是什么?
AIDL(Android Interface Definition Language)是Android提供的一种用于进程间通信(IPC)的机制。AIDL允许不同应用程序之间的通信,以及应用程序内的不同组件之间的通信。在AIDL中,定义接口和实现是分开的,客户端可以通过这个接口访问远程服务。通常情况下,服务提供者定义接口,而客户端使用这个接口与服务提供者通信。
在AIDL中,客户端和服务端使用相同的AIDL文件来定义接口。该文件包含要使用的方法和数据类型。然后,服务提供者使用AIDL文件生成一个Java接口实现,并将它注册到系统中。客户端使用这个Java接口来访问服务。
在AIDL中,客户端和服务端之间的通信是基于Binder机制实现的。Binder是Android系统中的一种IPC机制,它允许不同进程之间的通信。在AIDL中,服务提供者使用Binder将其服务对象注册到系统中,而客户端使用Binder访问该服务。
总的来说,AIDL提供了一种方便而强大的机制来实现安卓应用程序之间的进程间通信。使用AIDL,开发者可以在不同的应用程序之间共享数据和功能,实现更加灵活和强大的安卓应用程序。
二、使用步骤
1.构建一个服务提供者应用程序,其中包含一个服务,提供一个计算器功能
我们希望客户端应用程序能够通过这个服务使用计算器功能。
首先,我们需要创建一个AIDL文件来定义接口。在这个文件中,我们定义了一个add方法,用于将两个整数相加并返回结果。这个AIDL文件名为Calculator.aidl,内容如下:
interface ICalculator {
int add(int a, int b);
}
接下来,我们在服务提供者应用程序中创建一个CalculatorService类,它实现了ICalculator接口中定义的add方法。这个类的代码如下:
public class CalculatorService extends Service {
private final IBinder mBinder = new CalculatorBinder();
public class CalculatorBinder extends ICalculator.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
在这个代码中,CalculatorBinder类实现了ICalculator接口中定义的add方法。CalculatorService类通过返回一个CalculatorBinder对象来实现服务的绑定。
然后,我们需要在服务提供者应用程序的AndroidManifest.xml文件中注册CalculatorService类:
<service android:name=".CalculatorService" />
现在,服务提供者应用程序中的计算器服务已经准备好了。接下来,我们需要在客户端应用程序中使用这个服务。
我们需要创建一个AIDL文件,与服务提供者应用程序中的Calculator.aidl文件相同,然后将它添加到客户端应用程序的src/main/aidl目录下。客户端应用程序使用以下代码来绑定服务:
private ICalculator mCalculator;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mCalculator = ICalculator.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mCalculator = null;
}
};
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.calculatorapp", "com.example.calculatorapp.CalculatorService"));
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
这个代码中,我们创建了一个ServiceConnection对象,用于在服务连接成功或失败时接收通知。我们使用Intent来指定服务的包名和类名,并调用bindService方法来绑定服务。绑定成功后,我们可以使用mCalculator对象来调用add方法,并获取计算结果:
int result = mCalculator.add(3, 5);
这样,我们就成功地使用AIDL通信实现了一个简单的计算器服务。客户端应用程序可以通过这个服务来进行计算,并获取计算结果。
2.客户端应用程序和服务端应用程序
解释下这两个概念,在安卓应用程序中,通常会有一个或多个组件,例如Activity、Service、BroadcastReceiver和ContentProvider等。这些组件可以在同一个应用程序中使用,也可以在不同的应用程序之间使用。在AIDL通信中,客户端应用程序和服务端应用程序分别是指调用服务和提供服务的应用程序。例如,在同一部安卓终端设备上,客户端应用程序在本机的a软件上,服务端应用程序在本机的b软件上,这两个软件就可以通过aidl进行进程间通信,当a软件为调用服务方时就是客户端应用程序,b软件为提供服务的应用程序时,就是服务端应用程序。
3.举个支付功能的例子
举个实际工作中的例子,假设我们正在开发一个在线购物应用程序,其中需要使用到支付功能。我们可以将支付功能作为一个服务提供者应用程序,让不同的客户端应用程序都可以使用它。服务提供者应用程序中的服务可以提供以下功能:
1.支付:客户端应用程序可以调用服务来完成支付操作。
2.订单查询:客户端应用程序可以调用服务来查询订单信息。
3.优惠券查询:客户端应用程序可以调用服务来查询可用的优惠券信息。
服务提供者应用程序中的服务可以通过AIDL通信与客户端应用程序进行交互。客户端应用程序可以使用以下代码来绑定服务:
private IPaymentService mPaymentService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mPaymentService = IPaymentService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mPaymentService = null;
}
};
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.paymentservice", "com.example.paymentservice.PaymentService"));
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
这个代码中,我们创建了一个ServiceConnection对象,用于在服务连接成功或失败时接收通知。我们使用Intent来指定服务的包名和类名,并调用bindService方法来绑定服务。绑定成功后,我们可以使用mPaymentService对象来调用支付、订单查询和优惠券查询等方法。
服务提供者应用程序中的PaymentService类可以实现上述功能,同时通过AIDL文件定义服务接口,如下所示:
interface IPaymentService {
void pay(String orderId, double amount);
List<Order> getOrders(String userId);
List<Coupon> getCoupons(String userId);
}
在实际开发中,服务提供者应用程序和客户端应用程序可能会分别由不同的团队开发,这样可以实现团队之间的解耦。服务提供者应用程序可以提供通用的服务,供多个客户端应用程序使用。客户端应用程序可以通过绑定服务的方式,访问服务提供者应用程序中的服务。这样,客户端应用程序可以专注于自身的业务逻辑,而服务提供者应用程序则可以专注于服务的实现和优化。
支付功能作为一个服务提供者应用程序和客户端应用程序可以部署在同一台安卓终端上,也可以部署在不同的终端上。如果它们都部署在同一台终端上,那么客户端应用程序可以直接绑定到服务提供者应用程序中的服务来调用支付功能。如果它们部署在不同的终端上,那么客户端应用程序需要通过网络连接到服务提供者应用程序中的服务来调用支付功能。在这种情况下,服务提供者应用程序通常会提供一个网络接口(例如RESTful API或SOAP API),供客户端应用程序访问。
AIDL提供了一种跨进程通信(IPC)的机制,可以让不同的应用程序之间进行数据交换和调用。
如果服务提供者应用程序和客户端应用程序在不同的终端上,并且通过网络连接进行通信,那么它们可以使用网络协议(例如HTTP、TCP、UDP等)来进行数据交换。在这种情况下,通常使用RESTful API、SOAP API、gRPC等协议来定义接口和数据格式。
但是,如果服务提供者应用程序和客户端应用程序在同一台终端上,并且需要进行跨进程通信,那么使用AIDL可能是更好的选择。因为AIDL提供了一种轻量级、高效的跨进程通信机制,可以更方便地进行数据交换和服务调用,而且支持一些Android系统独有的特性(例如Binder机制),能够更好地支持Android应用程序的开发。
此外,AIDL也支持一些高级特性,例如多线程支持、传输大数据块等,能够满足一些特殊场景下的需求。
因此,如果服务提供者应用程序和客户端应用程序在同一台终端上,使用AIDL可能更适合进行跨进程通信。如果它们在不同的终端上,使用网络协议可能更合适。但是在实际开发中,也可以根据具体的需求和场景选择适合的通信方式。
AIDL是基于本地进程间通信机制的,无法跨越网络传递数据。在这种情况下,需要通过网络传递数据. Service和Client端的xxService.aidl文件名、文件内容、文件路径要相同
4.自研项目中用到aidl来进行app升级
我用的一块安卓底板上有供应商定制的安卓系统,同时供应商方面也烧录进去一款程序,“com.cvte.cyservice”,这款程序就是本案例中的服务器端程序,其中功能是为了app升级定制的,只要我在客户端程序(也就是我的自研app)提供升级后的app在安卓板子存储中的路径参数就可以让“com.cvte.cyservice"去把板子上原有的自研app卸载,把网络上下载好的现在存储在板子特定路径中的升级包安装上。以此来实现升级app的功能。
客户端程序:
上图注意看aidl路径和服务器端路径要保持一致:
// ISystemControlService.aidl
package com.cvte.cyservice;
// Declare any non-default types here with import statements
interface ISystemControlService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void systemCmd(String key, String value);
}
ServiceConnection mCon = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected START....");
ISystemControlService mService = ISystemControlService.Stub.asInterface((IBinder) service);
try {
if (MainActivity.me != null) {
MainActivity.me.destroyService();
}
Intent intent = new Intent(BroadcastConstant.BROADCAST_HEAR_VOICE_CONTROL);
intent.putExtra("extra_data", true);
LocalBroadcastManager.getInstance(Global.getContext()).sendBroadcast(intent);
new Thread() {
@Override
public void run() {
super.run();
ProgramUtils.sleep(2000);
try {
mService.systemCmd("install_App", file.getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
} catch (Exception e) {
e.printStackTrace();
}
Log.i(TAG, "onServiceConnected END....");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected....");
}
};
Intent intent = new Intent("com.cvte.cyservice.SystemControlService");
intent.setPackage("com.cvte.cyservice");
try {
Boolean res = context.bindService(intent, mCon, Context.BIND_AUTO_CREATE);
Log.i(TAG, "bindservice :" + res);
} catch (Exception e) {
e.printStackTrace();
}
至于“com.cvte.cyservice"该服务器端程序的代码我不知道,因为内部存储中的该程序烧录时使用了系统签名,我没权限,而且我也没这个程序的源代码。
5.注意事项
1.AIDL是基于本地进程间通信机制,只可以在同一个终端内进行进程间通信,若是客户端程序和服务器端程序不在同一个终端内则不能使用aidl通信,可以改用网络传输。
2.传递大量数据时容易出现性能问题,需要谨慎使用:当需要传递大量数据时,AIDL确实存在性能问题,因为AIDL底层采用的是序列化和反序列化的方式传递数据,而序列化和反序列化本身就需要消耗一定的时间和空间。因此,如果需要传递大量数据,建议使用其他IPC方式,比如Socket通信、共享内存等方式。
其中,Socket通信是一种常用的IPC方式,它可以在不同的进程之间传递大量数据,而且也可以在不同的机器之间进行通信。在Android中,可以使用Java的Socket API或者Android提供的Socket相关类(如LocalServerSocket、LocalSocket等)来实现Socket通信。不过,需要注意的是,Socket通信需要自己处理底层的通信细节,比如连接、发送、接收等操作,相对来说比较复杂,需要一定的开发经验和技巧。
另外,共享内存也是一种高效的IPC方式,它可以在不同的进程之间共享内存区域,从而实现数据的共享。在Android中,可以使用Binder驱动提供的共享内存机制或者使用Linux系统提供的共享内存机制来实现共享内存。不过,共享内存需要注意同步和互斥的问题,避免多进程同时访问导致数据不一致的情况发生。
6.总结
没总结