前段时间看着网上的一些文章,算是稍微学了点跨进程交互。虽然实现了AIDL的功能,但是还是好多不太理解,之后找了些资料,了解到跨进程交互其实有挺多的,如:Messenger,Socket,AIDL,Bundle...,所以决定把跨进程的常用的都写个记录,加深学习。
Messenger是一个轻量级的IPC交互,底层是AIDL实现的,但是一般都是一次处理一个请求。
以下的例子是在单一线程交互下,不存在并发交互的情况实现的跨进程交互。
我们先将例子的流程走一遍
首先是客户端先发送消息给服务器
之后服务器获取消息后返回消息给客户端
流程就这么简单,做了一个响应消息交互。下面就开始吧!
1.构建服务端Service
首先新建一个项目MyService
然后新建一个MessengerService类
代码如下:
package com.gjn.myservice;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case 0:
//获取消息
Log.e(TAG, "handleMessage: "+msg.getData().get("msg"));
//回复消息
Messenger reply = msg.replyTo;
Message reply_msg = Message.obtain(null,0);
Bundle data = new Bundle();
data.putString("reply","Service 回复消息给Client "+getTime());
reply_msg.setData(data);
try {
reply.send(reply_msg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
private static String getTime(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
return dateFormat.format(new Date());
}
}来解析下过程。
其中Messenger.getBinder对象就是服务的IBinder,这边就不多解释,getTime是用来获取当前时间的方法,也不多做解释。
我们来看下MessengerHandler这个类。
这个Handler是通过获取what=0的时候的消息。
获取为:msg中key为"msg"的数据,而这个数据就是客服端发上来的数据。
回复为:构建了一个Messenger 用来实现msg.replyTo,然后setData,最后在发送replyTo
2.构建客服端Client
首先新建一个项目MyClient
然后新建一个MessengerActivity类
布局界面说明:在客户端上面,页面布局我就加入了两个按钮,一个用来发送消息,一个用来获取消息。
布局界面代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.gjn.myclient.MessengerActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送MSG"
android:id="@+id/send_msg"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="162dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获取MSG"
android:id="@+id/get_msg"
android:layout_below="@+id/send_msg"
android:layout_centerHorizontal="true"
android:layout_marginTop="54dp" />
</RelativeLayout>
效果图:Activity类具体代码如下:
package com.gjn.myclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class MessengerActivity extends AppCompatActivity {
private Messenger mSendMsg;
private Messenger mGetMsg = new Messenger(new GetMsgHandler());
public static String reply;
private static class GetMsgHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case 0:
MessengerActivity.reply = msg.getData().getString("reply");
Log.e("MessengerActivity", "handleMessage: "+MessengerActivity.reply);
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mSendMsg = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
Intent intent = new Intent();
intent.setPackage("com.gjn.myservice");
intent.setAction("com.gjn.myservice.Messenger_Service");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Button sendButton = (Button) findViewById(R.id.send_msg);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = Message.obtain(null, 0);
Bundle data = new Bundle();
String string = "Client 向服务器发送消息"+getTime();
data.putString("msg", string);
msg.setData(data);
//设置获取msg的replyTo的Messenger
msg.replyTo = mGetMsg;
try {
mSendMsg.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
Toast.makeText(MessengerActivity.this, "发送消息:"+string, Toast.LENGTH_SHORT).show();
}
});
Button getButton = (Button) findViewById(R.id.get_msg);
getButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MessengerActivity.this, "获取消息:"+reply, Toast.LENGTH_SHORT).show();
}
});
}
private static String getTime(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
return dateFormat.format(new Date());
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
现在来解析下过程代码
1.构建两个Messenger对象
一个是用来做发送的Messenger对象:mSendMsg
一个是用来获取服务器返回消息的Messenger对象:mGetMsg
2.在构建Handler
GetMsgHandler是来用获取消息的Handler
3.在创建一个ServiceConnection
对象用来绑定服务。
4.onCreate设置
在onCreate中绑定服务,由于是跨项目的启动所以需要在intent中加入包名和action
5.onDestroy设置
在onDestroy中解除服务绑定
6.两个按钮的点击事件
SendButton用来发送消息
流程和上面服务器返回replyTo消息是一样的,这边就不多做解释了!
GetButton用来显示消息,因为服务器反馈的消息其实是在Handler里面就获取到了,这边显示了而已!
代码这边就讲解完了,这边说下重要的东西
那就是:AndroidManifest.xml 文件
由于是跨软件APP之间的交互,所以我们需要设置好
所以MyService的AndroidManifest.xml文件
完整代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gjn.myservice">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.gjn.myservice.Messenger_Service" />
</intent-filter>
</service>
</application>
</manifest>设置MessengerService的服务代码如下:
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.gjn.myservice.Messenger_Service" />
</intent-filter>
</service>这边来说下,因为是跨项目,所以需要设置action。
其中 com.gjn.myservice.Messenger_Service 就是在Client客户端上面设置的setAction内的参数。
然后客户端上面设置的包名是AndroidManifest.xml上面package的值 com.gjn.myservice
我们就是通过这两个参数来实现隐式开启别的项目的服务的。
代码讲解块就这样讲完了。
我们来看下结果吧!
本文详细介绍了一个简单的Messenger跨进程通信(IPC)示例,包括服务端Service和客户端Client的实现过程,涉及Messenger对象的构建、Handler的使用及AndroidManifest.xml配置等关键技术点。
1万+

被折叠的 条评论
为什么被折叠?



