PC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法。不仅是Android,其他语言也大很多情况下需要进程间通信的。Android本质上属于Linux,它的跨进程通信也基于Linux进程通信的原理。在Linux C编程中有几种方法
(1) 半双工Unix管道
(2) FIFOs(命名管道)
(3) 消息队列
(4) 信号量
(5) 共享内存
(6) 网络Socket
以上方法都可以实现进程间的通讯,但Android并没有使用以上6种现成的通信方法,而是自己开发Binder驱动,至于为什么重新开发Binder,可参考知乎上的回答:
https://www.zhihu.com/question/39440766?sort=created
大致原因:安全,性能,稳定。
本篇大致围绕下面几个问题,大致做出回答
因为在很多情况下,我们需要共享进程或者进程间通信,场景
1、下载的音乐文件在文件管理器中,当前我正在播放因为,我在文件管理器删除音乐(文件不存在了),当前音乐播放器是不是该停止呢?
2、第三方APP集成支付宝付款时,第三方应用怎么样调起支付宝用于支付呢
其实使用的场景很多,要实现上面的功能就得使用IPC。
内存共享
在用户空间中没有办法共享,因此进程间不能通信,但在内核空间中可以共享,不同的APP要进行通信,可以通过使用内核空间来做到,这样就产生IPC机制,IPC是用于解决这些问题的。为了做到IPC,Android 中提供了Binder机制,来解决进程通信问题
服务端:Binder服务端其实就是一个Binder对象,对象建立后,启动一个线程,这个线程接收Binder驱动发送的消息,并执行onTransact()方法,执行服务代码。
Binder驱动:当服务端对象创建时,同时会在Binder驱动中创建一个mRemote对象,该对象类型也是Binder类,客户端要过程访问时,都是通过mRemote对象。
客户端:客户端想要访问远程服务时,必须获取远程服务在B inder中对应的mRemote 对象,获取方法就是通过AIDL
AIDL(Android Interface Define Language),是android的一种接口定义语言。借助它,你可以定义接口,使得客户端和服务端之间实现进程间通信。
Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是android中的一种跨进程通信方式。通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。
也就是说Binder是用来实现远程服务访问的,AIDL则主要负责远程访问的主要内容,这些内容则用AIDL中的接口来描述。
示例做一个进程间通信的Demo,在AIDLServer中新建一个方法,返回一个字符串,在另一个Client的APP中调用。
1.创建一个AIDL文件:
// IMyAidlInterface.aidl
package com.example.aidlservice;
// 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);
String getString();
}
2、新建服务,这个服务就是远程访问的服务,用于客户端调用
package com.example.aidlservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
/**
* Created by yuxiaogang on 2017/8/5.
*/
public class RemoteService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iMyAidlInterface;
}
private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getString() throws RemoteException {
return "im from server";
}
};
}
3、启动服务:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_bind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_bind = (Button) findViewById(R.id.btn_bind);
btn_bind.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_bind:
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(MainActivity.this, "failed", Toast.LENGTH_SHORT).show();
}
}, BIND_AUTO_CREATE);
break;
}
}
}
客户端就是实际上需要调用远程服务,首先引进AIDL文件,注意AIDL文件的位置和包名。可以直接从Service中复制过来。编译后,客户端就可以调用到服务端的方法了
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_msg;
private TextView text;
private IMyAidlInterface iMyAidlInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_msg = (Button) findViewById(R.id.btn_msg);
text = (TextView) findViewById(R.id.text);
btn_msg.setOnClickListener(this);
}
@Override
protected void onResume() {
super.onResume();
Intent intent = new Intent();
intent.setAction("com.example.aidlservice.RemoteService");
// intent.setPackage("com.example.aidlservice");
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidlInterface=IMyAidlInterface.Stub.asInterface(service);
Log.i("MainActivity", "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("MainActivity", "onServiceDisconnected");
}
}, BIND_AUTO_CREATE);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_msg:
try {
text.setText(iMyAidlInterface.getString());
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
}