提到进程间通信首先想到就是aidl方式,本文除了介绍该方式外还会介绍通过Messenger实现,看到Messenger很容易想到Message(Messenger核心是通过Message和Handler进程通信),下面分别介绍这两种方式
一、Messenger方式
1、服务端创建Handler,来处理客户端发来的消息
2、通过Handler实例创建Messenger实例
3、在onBind(Intent intent)方法中返回messenger获得的IBinder实例
4、客户端绑定服务回调onServiceConnected方法通过IBinder获得服务端的Messenger实例
5、客户端通过messenger发送消息到服务端
(1)服务端主要代码:
public class MyService extends Service {
private Messenger messenger;
private Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i("aa", "**收到消息");
Toast.makeText(MyService.this, "收到消息!", Toast.LENGTH_SHORT).show();
}
};
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
messenger = new Messenger(mHandler);
return messenger.getBinder();
}
}
(2)客户端主要代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Messenger messenger;
private ServiceConnection connection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
messenger = new Messenger(iBinder);
}
@Override public void onServiceDisconnected(ComponentName componentName) {
messenger = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt1 = (Button)findViewById(R.id.act_bt1);
Button bt2 = (Button)findViewById(R.id.act_bt2);
bt1.setOnClickListener(this);
bt2.setOnClickListener(this);
}
@Override public void onClick(View view) {
switch (view.getId()){
case R.id.act_bt1:
Intent intent = new Intent();
intent.setAction("com.huizhong.service");
intent.setPackage("com.huizhong.onedemo");//不设置包名会报异常
bindService(intent, connection, Context.BIND_AUTO_CREATE);
break;
case R.id.act_bt2:
if (messenger == null){
Toast.makeText(MainActivity.this, "请先绑定服务", Toast.LENGTH_SHORT).show();
}else {
try {
Message message = new Message();
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
}
}
}
注意事项:
a.首先要开启服务端的服务再用客户端绑定。
b.客户端绑定服务要setPackage(String pack)设置服务端服务的包名
二、AIDL方式(双进程保活案例)
1、新建GuardAidl.aidl文件(注意目录结构为aidl/包名/*.aidl),然后clean工程
2、创建本地服务WindowService和新进程服务KeepLiveService
注:android:process值以:开头表示私有进程,以字母开头表示全局进程
3、修改WindowService服务
(1)定义内部类MyBinder继承GuardAidl.Stub,并在onBinder方法中返回该实例
(2)创建ServiceConnection实例,重写onServiceDisconnected方法,在其中开启并绑定保活服务
(3)重写onStartCommand方法,在其中开启并绑定保活服务
4、修改KeepLiveService服务
(1)定义内部类MyBinder继承GuardAidl.Stub,并在onBinder方法中返回该实例
(2)创建ServiceConnection实例,重写onServiceDisconnected方法,在其中开启并绑定本地服务
(3)重写onStartCommand方法,在其中绑定本地服务
三、aidl(不同APP通信案例)
1、服务端
(1)定义.aidl文件(目录main/aidl/包名【可自定义,但服务端与客户端必须一样】/.aidl)
package com.lpf.myapplication;
interface IMyAidlInterface {
int test(int a, int b);
}
(2)rebuild项目,定义类继承IMyAidlInterface.Stub
public class MyAidlBinder extends IMyAidlInterface.Stub {
@Override
public int test(int a, int b) {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return a + b;
}
}
(3)定义service服务
class MyService : Service() {
var aa = ""//这是intent传参
override fun onBind(intent: Intent): IBinder? {
aa = intent.getStringExtra("aa")
Log.e("aa", "********onBind:" + intent.getStringExtra("aa"))
return MyAidlBinder()
}
}
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.lpf.myapplication.MyService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
2、客户端
(1)拷贝服务端aidl目录(aidl/包名/.aidl)
(2)rebuild项目
(3)绑定服务
private IMyAidlInterface mMyAidlImpl;
private ServiceConnection mConnect = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//此处service是代理对象,需要以下方法获取aidl接口对象
mMyAidlImpl = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mMyAidlImpl = null;
}
};
//绑定远程服务
private void bindAidlService(){
Intent intent = new Intent("com.hualala.xiaoding.myapplication.MyService");
intent.setPackage("com.hualala.xiaoding.myapplication");
intent.putExtra("aa", "这是传参");
getActivity().bindService(intent, mConnect, Context.BIND_AUTO_CREATE);
}
//和服务端通讯
private void sendMessage(){
if (mMyAidlImpl != null){
new Thread(() -> {
try {
int result = mMyAidlImpl.test(1, 8);
} catch (RemoteException e) {
e.printStackTrace();
}
}).start();
}else {
Log.e("aa", "********先绑定服务")
}
}
注:
【1】由于服务端test(int a, int b)方法运行线程依赖于客户端调用该方法的线程,案例模拟耗时操作,而sendMessage()在主线程调用需要开启子线程。
【2】客户端可以执行多次绑定操作(只会创建一个,且不影响生命周期),客户端退出,服务端service自动销毁