IPC通信方式
Posted 陳英傑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IPC通信方式相关的知识,希望对你有一定的参考价值。
IPC又称进程间通信,面试老生常谈的问题,Linux常用方式有:管道、信号、消息队列、共享内存、内存映射、信号量、套接字。
android进程间通信方式:
Intent、Broastcast,AIDL、Messenger、ContentProvider、Binder、Socket。
一、Intent
这个平时用的最多的,就不多说了
二、Broastcast
广播也比较简单,简单列举一下知识点:
四大组建之一
分类
标准广播:也叫无需广播,所有广播接收器都能接收到广播,无法拦截,效率高。
有序广播:优先级高的先接收到,逻辑执行完往下传递,前面的广播接收器可以拦截广播。
注册方式
静态注册:在AndroidManifest.xml中,应用存活着就会一直处于接收状态。
动态注册:在代码中注册,可以手动解除注册。
其中有序广播需要设置优先级priority。
注意:不要在 onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当onReceive()方法运行了较长时间而没有结束时,程序就会报错。因此广播接收器更多的是扮演一种打开程序其它组件的角色,比如创建一条状态栏通知,或者启动一个服务等。
三、AIDL
aidl是IPC机制的一种解决方案,使用起来相对Messenger等稍微复杂,简单例子如下:
简单使用
1、服务端
首先创建服务端的应用,app/src/main下创建aidl文件,这里只定义了一个方法,传进来一个字符串,经过服务端处理在返回给客户端:
package com.lianzhuoxinxi.baoduoduo;
import com.lianzhuoxinxi.baoduoduo.User;
interface IMyAidlInterface
String getName(String str);
然后rebuild一下之后会根据此文件生成对应接口类
接下来就是服务端的处理代码,创建一个Service,它里面有一个aidl接口的实现,主要在这里面处理数据,然后返回给客户端:
public class MyRemoteService extends Service
@Nullable
@Override
public IBinder onBind(Intent intent)
return new MyBinder();
private class MyBinder extends IMyAidlInterface.Stub
@Override
public String getName(String str) throws RemoteException
if (!TextUtils.isEmpty(str))
// 把客户端传过来的字符串转大写返回给客户端
return str.toUpperCase();
return "empty";
最后在AndroidManifest.xml中注册服务,这里有三个属性要注意,enabled必须为true,false表示被禁用;exported为true表示能与其他应用交互,false表示此服务只能在应用内使用;action是客户端绑定使用的。
<service android:name=".service.MyRemoteService"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="lzxx.bd.aidl.service"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
服务端就这么简单,运行起来就行了。
2、客户端
首先创建一个客户端应用,然后把服务端的aidl文件(包括包名)拷贝过来,这里注意保证文件的包名一定要和服务端一样,所以最保险的方式就是拷贝。
在MainActivity中绑定服务,当绑定成功就可以调用服务端aidl中定义的方法了。
private void aidlTest()
// 此处action和服务端配置的一致,必须设置服务端应用的包名,否则找不到。
Intent intent = new Intent("lzxx.bd.aidl.service");
intent.setPackage("com.lianzhuoxinxi.baoduoduo");
bindService(intent, new ServiceConnection()
@Override
public void onServiceConnected(ComponentName name, IBinder service)
aidlInterface = IMyAidlInterface.Stub.asInterface(service);
@Override
public void onServiceDisconnected(ComponentName name)
, BIND_AUTO_CREATE);
private void getNameFromServer()
try
Log.e("AIDL", ">>>>" + aidlInterface.getName("hello aidl"));
catch (RemoteException e)
e.printStackTrace();
打印结果如下,可以看到服务端的处理逻辑起作用了。
2020-11-27 09:58:40.633 25189-25189/? E/AIDL: >>>>HELLO AIDL
自定义数据类型
1、服务端
在刚才的aidl文件中增加两个方法,一个是添加用户,一个是获取用户列表
interface IMyAidlInterface
String getName(String str);
List<User> getUserList();
void addUser(inout User user);
创建一个用户实体类,需要实现Parcelable接口,并且需要添加一个readFromParcel方法
public class User implements Parcelable
private String name;
private int age;
public String getName()
return name;
public void setName(String name)
this.name = name;
public int getAge()
return age;
public void setAge(int age)
this.age = age;
@Override
public int describeContents()
return 0;
@Override
public void writeToParcel(Parcel dest, int flags)
dest.writeString(this.name);
dest.writeInt(this.age);
public void readFromParcel(Parcel parcel)
name = parcel.readString();
age = parcel.readInt();
public User()
protected User(Parcel in)
this.name = in.readString();
this.age = in.readInt();
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>()
@Override
public User createFromParcel(Parcel source)
return new User(source);
@Override
public User[] newArray(int size)
return new User[size];
;
同时在aidl文件夹中再创建一个User.aidl文件,声明自定义的数据类型
package com.lianzhuoxinxi.baoduoduo;
parcelable User;
Service中也实现新增加的方法:
public class MyRemoteService extends Service
private List<User> users;
@Override
public void onCreate()
super.onCreate();
users = new ArrayList<>();
@Nullable
@Override
public IBinder onBind(Intent intent)
return new MyBinder();
private class MyBinder extends IMyAidlInterface.Stub
@Override
public String getName(String str) throws RemoteException
if (!TextUtils.isEmpty(str))
return str.toUpperCase();
return "empty";
@Override
public List<User> getUserList() throws RemoteException
return users;
@Override
public void addUser(User user) throws RemoteException
users.add(user);
编译之后运行起来。
目录结构:
2、客户端
同样把aidl文件夹拷贝过来,把User类连同包名拷贝过来,目录结构:
其他不用修改,编译之后就可以调用新加的addUser()和getUserList()方法了。
四、Messenger
基于Binder的一种进程间通信方式
1、服务端
创建一个service用来接收请求并返回结果:
public class MessengerService extends Service
private Messenger serverMessenger = new Messenger(new MessengerHandler());
@Override
public void onCreate()
super.onCreate();
@Nullable
@Override
public IBinder onBind(Intent intent)
return serverMessenger.getBinder();
@Override
public int onStartCommand(Intent intent, int flags, int startId)
return super.onStartCommand(intent, flags, startId);
@Override
public void onDestroy()
super.onDestroy();
private static class MessengerHandler extends Handler
@Override
public void handleMessage(@NonNull Message msg)
super.handleMessage(msg);
Bundle data = msg.getData();
String type = data.getString(Cons.client_key);
Message message = Message.obtain();
Bundle bundle = new Bundle();
if ("1".equals(type))
bundle.putString(Cons.server_key, "request type 1 response");
else if ("2".equals(type))
bundle.putString(Cons.server_key, "request type 2 response");
else
bundle.putString(Cons.server_key, "request unknown type response");
message.setData(bundle);
try
msg.replyTo.send(message);
catch (RemoteException e)
e.printStackTrace();
2、客户端
- 实现ServiceConnection接口,实例化发送请求的messenger对象:
private class MyServiceConnection implements ServiceConnection
private String type;
public MyServiceConnection(String type)
this.type = type;
@Override
public void onServiceConnected(ComponentName name, IBinder service)
// 1、get connection from server
if (“1”.equals(type))
messenger1 = new Messenger(service);
else if (“2”.equals(type))
messenger2 = new Messenger(service);
else
messengerX = new Messenger(service);
@Override
public void onServiceDisconnected(ComponentName name)
;
- 绑定服务:
这里创建了3个连接相当于3个客户端请求,共用同一个服务。
connection1 = new MyServiceConnection(type_1);
connection2 = new MyServiceConnection(type_2);
connectionX = new MyServiceConnection("");
bindService(new Intent(this, MessengerService.class), connection1, BIND_AUTO_CREATE);
bindService(new Intent(this, MessengerService.class), connection2, BIND_AUTO_CREATE);
bindService(new Intent(this, MessengerService.class), connectionX, BIND_AUTO_CREATE);
- 创建一个Handler来接收服务器返回结果:
private static class ClientHandler extends Handler
private WeakReference<MessengerActivity> reference;
public ClientHandler(MessengerActivity activity)
this.reference = new WeakReference<>(activity);
@Override
public void handleMessage(@NonNull Message msg)
super.handleMessage(msg);
MessengerActivity activity = reference.get();
Bundle data = msg.getData();
String serverData = data.getString(Cons.server_key);
activity.updateResult(serverData);
private void updateResult(String str)
result.append(str).append("\\n");
tvResult.setText(result.toString());
- 实例化接收请求结果的Messenger对象:
private Messenger clientMessenger = new Messenger(new ClientHandler(this));
- 然后是发送请求的方法:
这里创建Message对象千万别用new,因为牵扯到内存抖动问题,这里不过多介绍。
private void sendData(String type)
// 2、create Message
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString(Cons.client_key, type);
message.setData(bundle);
// 3、data receive object
message.replyTo = clientMessenger;
try
// 4、send request
if (type_1.equals(type))
messenger1.send(message);
else if (type_2.equals(type))
messenger2.send(message);
else
messengerX.send(message);
catch (RemoteException e)
e.printStackTrace();
发送请求:
// 发送类型1请求
sendData("1");
// 发送类型2请求
sendData("2");
// 发送其他类型请求
sendData("");
最后在activity的onDestroy()方法中解绑服务:
@Override
protected void onDestroy()
super.onDestroy();
unbindService(connection1);
unbindService(connection2);
unbindService(connectionX);
随便点击调用sendData方法之后结果:
五、ContentProvider
- ContentProvider是Android中提供的专门用于不同应用间数据共享的方式,从这一点来看,他肯定是支持进程间通信的,和Messenger一样,他的底层实现也是Binder,由此可见,Binder在Android系统中的重要性
- ContentProvider比Messenger使用起来要简单的多了,因为系统已经为我们做了封装,我们无需关心底层即可轻松实现IPC
- 系统预置了好多ContentProvider,比如通讯录信息,日程表信息,等,要跨进程访问这些信息,只需要通过ContentProvider的query,updata,insert,delete方法即可
接下来简单使用它,创建一个ContentProvider:
public class MContentProvider extends ContentProvider
@Override
public boolean onCreate()
Log.e(getClass().getSimpleName(), "onCreate Thread: " + Thread.currentThread());
return false;
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder)
Log.e(getClass().getSimpleName(), "query() Thread : " + Thread.currentThread());
MatrixCursor cursor = new MatrixCursor(new String[]"name", "age", "city", 5);
cursor.addRow(new String[]"张伟", "39", "北京");
cursor.addRow(new String[]"王刚", "21"以上是关于IPC通信方式的主要内容,如果未能解决你的问题,请参考以下文章