ad ipc_android ipc

Android (66) 2023-09-13 19:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说ad ipc_android ipc,希望能够帮助你!!!。

今天来讲讲AIDL,这个神秘的AIDL,也是最近在学习的,看了某课大神的讲解写下的blog,希望结合自己的看法给各位同价通俗易懂的讲解

官方文档:http://developer.android.com/guide/components/aidl.html

一.What is AIDL?(什么是AIDL)

AIDL:Android Interface Definition Language (Android接口定义语言)

首先,我们要知道,进程1和进程2,我们要如何让他通讯?

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第1张

在Android系统的虚拟机中,每一个app运行都是在一个独立的沙箱里面的,这样的话,一个应用崩溃也不会影响到其他应用,这样我们就提出了一个问题,跨进程如如何进行通讯?如何传递数据?其实两个进程是不能直接通讯的,他需要Android系统底层的帮助来进行通讯!那就是我们每个人都知道的四大组件

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第2张

我们首先还是先进Google的API看看

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第3张

他大概的意思是他允许你去定义一个自己的标准,使用的是IPC(进程间通讯)进制,跨进程通讯,有兴趣的可以去翻译一下,不过值得注意的是他的第二段标记

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第4张

这里提到了两个东西

- Binder

- Messenger

我们继续往下看话就知道

- Binder

- Messenger

翻译:如果您不需要执行并发IPC在不同的应用程序中 你就用Binder ,或者如果你想执行IPC,但不需要处理多线程,实现你的接口Messenger,无论如何,确保你了解实现AIDL之前绑定服务。

所以我们就能理清楚AIDL的概念了

AIDL //IPC 多应用 多线程

二.Defining an AIDL Interface(语法)

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第5张

文档中强调。你必须定义一个.aidl的文件,那我们怎样去创建尼?

1. Create the .aidl file(创建一个.aidl文件)

官方提供的语法

// IRemoteService.aidl

package 包名(com.lgl.android);

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

/** Example service interface 接口*/

interface IRemoteService {

/** Request the process ID of this service, to do evil things with it. 方法*/

int getPid();

/** 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);

}

我们来做一个简单的演示

我们要使用的编译工具在我们的SDK/buidl-tools/android版本/aidl.bat,不过实际开发中也不需要手动编译,我们新建一个项目ForAIDL,这里我们使用的开发工具是Android Studio,其实Eclipse可能更加让人熟悉,不过用AS也是大势所趋了,而且AS的目录结构我也很喜欢

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第6张

我们直接java-new - folder - AIDL folder

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第7张

然后你就会发现多了一个aidl的文件夹

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第8张

我们继续新建一个包名,新建一个文件文件new - AIDL - file

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第9张

大致的内容

// IMyAidlInterface.aidl

package com.lgl.foraidl;

// 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);

}

AS默认是不会去重新构建Gradle,我们点击一下构建按钮

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第10张

然后我们就可以在MainActivity中调用了

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第11张

三.AIDL Client And Service(客户端和服务端)

现在就好玩了,我们先来理理思路,一般是这样的,我们一个软件有某个功能,也就是服务端,然后客户端通过AIDL去访问

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第12张

这里可以看到服务端只是处理一些操作,我们客户端去请求,这样的话,那我创建一个AIDLService,同样的,我们需要去创建AIDL文件,命名-ServiceAidlInterface

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第13张

ServiceAidlInterface

// ServiceAidlInterface.aidl

package com.lgl.aidlservice;

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

interface ServiceAidlInterface {

/*

*计算两数之和

*/

int add(int num1,int num2);

}

现在我们处理的就不是默认的东西了,AIDL的原理就是你自定义语言接口,对的,我们也来

2. Implement the interface(实现一个AIDL)

根据我们的Google文档,第一步Create the .aidl file已经完成了,现在就来进行第二步了,我们这里需要使用到Service,看文档

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第14张

这样的话我们新建一个IRemoteService继承service,我们实现计算的逻辑处理

package com.lgl.aidlservice;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

/**

*

* 监听服务

* Created by lgl on 16/3/13.

*/

public class IRemoteService extends Service{

/**

* 当客户端绑定到该服务的时候启动onBind

* @param intent

* @return

*/

@Override

public IBinder onBind(Intent intent) {

//绑定之后就计算

return iBinder;

}

/**

* 开始处理结果

*/

private IBinder iBinder = new ServiceAidlInterface.Stub(){

@Override

public int add(int num1, int num2) throws RemoteException {

Log.i("AIDL","收到了请求,參數1"+num1+"參數2"+num2);

return num1+num2;

}

};

}

3. Expose the interface to clients(客户端的实现)

OK,写完了服务端就可以写客户端了,我们直接new一个Module-AIDLClients

我們先按剛才的逻辑,把界面写了

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第15张

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:gravity="center"

android:padding="15dp">

<TextView

android:text="AIDL"

android:textSize="50sp"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

<EditText

android:hint="请输入数字1"

android:id="@+id/et_num1"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

<TextView

android:layout_marginBottom="15dp"

android:layout_marginTop="15dp"

android:textSize="20sp"

android:text="+"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

<EditText

android:hint="请输入数字2"

android:id="@+id/et_num2"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

<TextView

android:layout_marginBottom="15dp"

android:layout_marginTop="15dp"

android:textSize="20sp"

android:text="="

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

<TextView

android:id="@+id/tv_result"

android:text="结果:"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

<Button

android:textColor="#fff"

android:background="@android:color/holo_blue_light"

android:layout_marginTop="30dp"

android:id="@+id/btn_ok"

android:text="计算"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

</LinearLayout>

我们要想客户端调用服务端的内容,那么就一定要定义标准的语言,所以客户端的aidl和服务端必须一致

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第16张

记住,每次不通过的时候先编译一遍

MainActivity(客户端)

package com.lgl.aidlclients;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.IBinder;

import android.os.RemoteException;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import com.lgl.aidlservice.ServiceAidlInterface;

/**

* AIDL 客户端

* @author lgl

*/

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

//输入

private EditText et_num1,et_num2;

//结果

private TextView tv_result;

//AIDL远程访问

private Button btn_ok;

private ServiceAidlInterface aidl;

private ServiceConnection conn = new ServiceConnection() {

//连接上

@Override

public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

//拿到远程服务

aidl = ServiceAidlInterface.Stub.asInterface(iBinder);

}

//断开时

@Override

public void onServiceDisconnected(ComponentName componentName) {

//回收

aidl = null;

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

bindServices();

}

private void initView() {

et_num1 = (EditText) findViewById(R.id.et_num1);

et_num2 = (EditText) findViewById(R.id.et_num2);

tv_result = (TextView) findViewById(R.id.tv_result);

btn_ok = (Button) findViewById(R.id.btn_ok);

btn_ok.setOnClickListener(this);

}

@Override

public void onClick(View view) {

switch (view.getId()){

case R.id.btn_ok:

int num1 = Integer.parseInt(et_num1.getText().toString());

int num2 = Integer.parseInt(et_num2.getText().toString());

try {

//结果

int res = aidl.add(num1,num2);

tv_result.setText("结果:"+res);

} catch (RemoteException e) {

e.printStackTrace();

}

break;

}

}

/**

* 开启服务

*/

private void bindServices() {

//获取服务端

Intent intent = new Intent();

//5.0之后的改变

intent.setComponent(new ComponentName("com.lgl.aidlservice","com.lgl.aidlservice.IRemoteService"));

//绑定服务

bindService(intent,conn, Context.BIND_AUTO_CREATE);

}

/**

* 销毁服务

*/

@Override

protected void onDestroy() {

super.onDestroy();

unbindService(conn);

}

}

这里逻辑也是十分的清晰,你创建了之后启动服务,我调用方法来计算,我们来演示一下,我们先启动服务端,再启动客户端

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第17张

记得注册

<service android:name=".IRemoteService"

android:process=":remote"

android:exported="true" >

<intent-filter>

<category android:name="android.intent.category.DEFAULT" />

<action android:name="com.lgl.aidlservice.IRemoteService" />

</intent-filter>

</service>

写到这里才看到玉刚也写了相关的信息,这边android:exported="true"为权限问题,具体可以看下:

[android跨进程通信(IPC):使用AIDL](http://blog.csdn.net/singwhatiwanna/article/details/17041691)

不过这终究也只是一些小菜,我们项目中也不可能用到这么low的方法,毕竟AIDL还是很强大的,既然这样,那我们来玩玩高级一点的

四.AIDL数据传递

我们不能传递很大的数据这是总所周知的,那AIDL默认支持什么类型的尼?我们可不可以自定义尼?当然可以

1.默认数据类型

我们可以看一下官方文档

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第18张

- 1.基本数据类型

- 2.String

- 3.CharSequence

- 4.List

- 5.Map

- 6.Parcelable(序列化)

我们新建一个aidl文件,他都会自己生成一个方法

void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,

double aDouble, String aString);

意指的就是基础类型

然而在我们的实际测试中,你会发现他是不支持short的,我们做这样的小测试

void basicTypes(byte b,short s, int anInt, long aLong, boolean aBoolean, float aFloat,

double aDouble, String aString);

然后编译

/Users/lgl/Documents/Android/ASCode/AIDLService/app/src/main/aidl/com/lgl/aidlservice/IMyAidlInterface.aidl:11 parameter s (2) unknown type short

他报的错误就是不支持short

再比如说,你想写一个List< String>list的数据,你必须指定他是in还是out类型的

in List< String>list

2.自定义类型

这里我们先在服务端新建一个aidl文件-IMyAidlInterface,然后写入我们的方法

//我们返回的数据是一个List集合

List<Person>add(in Person person);

这里报错是毋庸置疑的,因为他不识别我们的Person,但是就算我们新建一个Person类也是无用的,因为aidl不支持这个类型,上面也说了,他只支持基本类型和其他有限的几种数据类型,这样的话,我们就需要自定义了,怎么来呢?让他implements Parcelable就可以

package com.lgl.aidlservice;

import android.os.Parcel;

import android.os.Parcelable;

/**

* 序列化实体类

* Created by lgl on 16/3/15.

*/

public class Person implements Parcelable{

private String name;

private int age;

//构造方法

public Person(String name,int age){

this.name =name;

this.age = age;

}

protected Person(Parcel in) {

name = in.readString();

age = in.readInt();

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

@Override

public int describeContents() {

return 0;

}

@Override

public void writeToParcel(Parcel parcel, int i) {

parcel.writeString(name);

parcel.writeInt(age);

}

public static final Creator<Person> CREATOR = new Creator<Person>() {

@Override

public Person createFromParcel(Parcel in) {

return new Person(in);

}

@Override

public Person[] newArray(int size) {

return new Person[size];

}

};

}

这里值得注意的就是读写部分了,你是怎么写的就得怎么读,顺序错了就没用了,那我们编译一下,你会发现他还是提示错误,依然是位置的List数据类型

/Users/lgl/Documents/Android/ASCode/AIDLService/app/src/main/aidl/com/lgl/aidlservice/IMyAidlInterface.aidl:9 unknown return type List<Person>

这里就需要我们手动导入这个Person了不然人家也不认识啊!那要怎么做?还是需要创建一个Person的AIDL文件,内容十分的简单,说明文件

// IMyAidlInterface.aidl

package com.lgl.aidlservice;

parcelable Person;

可以看到,里面就一句话,好的,现在编译通过了,那我们重新来修改一下IRemoteService了,这次就不是返回计算数据的和了

package com.lgl.aidlservice;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteException;

import java.util.ArrayList;

import java.util.List;

/**

*

* 监听服务

* Created by lgl on 16/3/13.

*/

public class IRemoteService extends Service{

private ArrayList<Person>persons;

/**

* 当客户端绑定到该服务的时候启动onBind

* @param intent

* @return

*/

@Override

public IBinder onBind(Intent intent) {

persons = new ArrayList<Person>();

//绑定之后就计算

return iBinder;

}

/**

* 开始处理结果

*/

// private IBinder iBinder = new ServiceAidlInterface.Stub(){

//

// @Override

// public int add(int num1, int num2) throws RemoteException {

// Log.i("AIDL","收到了请求,參數1"+num1+"參數2"+num2);

// return num1+num2;

// }

// };

/**

* 序列化

*/

private IBinder iBinder = new IMyAidlInterface.Stub(){

@Override

public List<Person> add(Person person) throws RemoteException {

//每增加一个人都能得到返回

persons.add(person);

return persons;

}

};

}

好的,服务端部分写完了,刚开始可能是有点混乱的,不过当你确实已经理解之后你会发现,也就这么点东西的逻辑,那我们继续来写客户端,看他是怎么进行序列化的处理的。

还是一样,我们把Person.aidl和IMyAidlInterface.aidl复制过去,顺便把Person类拷贝过来,这里要注意的事就是包名要一致

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第19张

然后我们就开启服务了

package com.lgl.aidlclients;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.IBinder;

import android.os.RemoteException;

import android.support.v7.app.AppCompatActivity;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import com.lgl.aidlservice.IMyAidlInterface;

import com.lgl.aidlservice.Person;

import com.lgl.aidlservice.ServiceAidlInterface;

import java.util.ArrayList;

/**

* AIDL 客户端

* @author lgl

*/

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

//输入

private EditText et_num1,et_num2;

//结果

private TextView tv_result;

//AIDL远程访问

private Button btn_ok;

private ServiceAidlInterface aidl;

private IMyAidlInterface imy;

private ServiceConnection conn = new ServiceConnection() {

//连接上

@Override

public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

//拿到远程服务

aidl = ServiceAidlInterface.Stub.asInterface(iBinder);

imy = IMyAidlInterface.Stub.asInterface(iBinder);

}

//断开时

@Override

public void onServiceDisconnected(ComponentName componentName) {

//回收

aidl = null;

imy = null;

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

bindServices();

initView();

}

private void initView() {

et_num1 = (EditText) findViewById(R.id.et_num1);

et_num2 = (EditText) findViewById(R.id.et_num2);

tv_result = (TextView) findViewById(R.id.tv_result);

btn_ok = (Button) findViewById(R.id.btn_ok);

btn_ok.setOnClickListener(this);

}

@Override

public void onClick(View view) {

switch (view.getId()){

case R.id.btn_ok:

// int n1 = Integer.parseInt(et_num1.getText().toString());

// int n2 = Integer.parseInt(et_num2.getText().toString());

//

// try {

// //结果

// int res = aidl.add(n1,n2);

// tv_result.setText("结果:"+res);

// } catch (RemoteException e) {

// e.printStackTrace();

// tv_result.setText("Error");

// }

try{

ArrayList<Person>persons = (ArrayList<Person>) imy.add(new Person("name",21));

Log.i("Person",persons.toString());

}catch (RemoteException e){

e.printStackTrace();

}

break;

}

}

/**

* 开启服务

*/

private void bindServices() {

//获取服务端

Intent intent = new Intent();

//5.0之后的改变

intent.setComponent(new ComponentName("com.lgl.aidlservice","com.lgl.aidlservice.IRemoteService"));

//绑定服务

bindService(intent,conn, Context.BIND_AUTO_CREATE);

}

/**

* 销毁服务

*/

@Override

protected void onDestroy() {

super.onDestroy();

unbindService(conn);

}

}

这样的话,只要我们点击了计算按钮,Log打印一条消息,那事实是如此吗?我们运行一下

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第20张

不会发现,我们每一次添加都是多增加了一行,相当于我们远程添加了一行

五.AIDL的工作原理

我们每次编译AIDL的文件的时候,都会编译成一个JAVA文件,具体是什么,我们一起研究研究,借用大神的一张图,你现在可能看不懂,等讲完原理你就懂了

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第21张

编译好的JAVA文件在

ad ipc_android ipc_https://bianchenghao6.com/blog_Android_第22张

/*

* This file is auto-generated. DO NOT MODIFY.

* Original file: /Users/lgl/Documents/Android/ASCode/AIDLService/aidlclients/src/main/aidl/com/lgl/aidlservice/IMyAidlInterface.aidl

*/

package com.lgl.aidlservice;

//他是继承系统的接口,也就是说他本身就是一个接口

public interface IMyAidlInterface extends android.os.IInterface

{

/** 存根,并且实现了自己的接口*/

public static abstract class Stub extends android.os.Binder implements com.lgl.aidlservice.IMyAidlInterface

{

private static final java.lang.String DESCRIPTOR = "com.lgl.aidlservice.IMyAidlInterface";

/**自己的构造方法*/

public Stub()

{

this.attachInterface(this, DESCRIPTOR);

}

/**

* Cast an IBinder object into an com.lgl.aidlservice.IMyAidlInterface interface,

* generating a proxy if needed.

*/

public static com.lgl.aidlservice.IMyAidlInterface asInterface(android.os.IBinder obj)

{

if ((obj==null)) {

return null;

}

android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

if (((iin!=null)&&(iin instanceof com.lgl.aidlservice.IMyAidlInterface))) {

return ((com.lgl.aidlservice.IMyAidlInterface)iin);

}

return new com.lgl.aidlservice.IMyAidlInterface.Stub.Proxy(obj);

}

@Override public android.os.IBinder asBinder()

{

//返回的this是Stub

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_add:

{

data.enforceInterface(DESCRIPTOR);

com.lgl.aidlservice.Person _arg0;

if ((0!=data.readInt())) {

//如果拿到传过来数值封装成一个data

_arg0 = com.lgl.aidlservice.Person.CREATOR.createFromParcel(data);

}

else {

_arg0 = null;

}

java.util.List<com.lgl.aidlservice.Person> _result = this.add(_arg0);

reply.writeNoException();

//最后通过这个又写回去了,这样就完成了整个的通讯

reply.writeTypedList(_result);

return true;

}

}

return super.onTransact(code, data, reply, flags);

}

//代理,他是Stud的内部类

private static class Proxy implements com.lgl.aidlservice.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;

}

//我们返回的数据是一个List集合

@Override public java.util.List<com.lgl.aidlservice.Person> add(com.lgl.aidlservice.Person person) throws android.os.RemoteException

{

android.os.Parcel _data = android.os.Parcel.obtain();

android.os.Parcel _reply = android.os.Parcel.obtain();

java.util.List<com.lgl.aidlservice.Person> _result;

try {

//写入了类名

_data.writeInterfaceToken(DESCRIPTOR);

if ((person!=null)) {

//写了一个1,同时add数据,当你拿到了远程服务的时候,其实你拿到的只是远程服务的代理

_data.writeInt(1);

person.writeToParcel(_data, 0);

}

else {

_data.writeInt(0);

}

//传入到onTransact

mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);

_reply.readException();

_result = _reply.createTypedArrayList(com.lgl.aidlservice.Person.CREATOR);

}

finally {

_reply.recycle();

_data.recycle();

}

return _result;

}

}

static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

}

//我们返回的数据是一个List集合

//我们创建AIDL命名的这个方法

public java.util.List<com.lgl.aidlservice.Person> add(com.lgl.aidlservice.Person person) throws android.os.RemoteException;

}

Ok,AIDL这边算是讲完了,如果有兴趣的话,可以再去深入研究一下,我这边也只是学习了大神的视频,然后做的一个小总结和小笔记

Demo下载:http://download.csdn.net/detail/qq_26787115/9462515

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

发表回复