您的位置:首页 > 其它

跨进程通信Messenger和HandlerThread

2015-08-13 15:30 295 查看
进程间的通信首先想到的是AIDL,写AIDL文件实在是麻烦,维护起来也麻烦,不喜欢。

Messenger 也可以实现进程间通信的功能,看了一些牛人写的帖子,今天咱也学习和记录一下,便于以后查询。

参考 :
http://blog.csdn.net/h3c4lenovo/article/details/7915392 http://blog.csdn.net/lmj623565791/article/details/47079737
1、客户端通过绑定到服务端的server上获得服务端的Messenger对象,然后向服务端的server发送消息。(Messenger.send(Message))

2、客户端在向Server发送消息的同时把客户端的回调(Messenger对象)也带到服务端(msgFromClient.replyTo = mMessenger),
      待服务端计算完成后通过回调返回到客户端 : Messenger callBack = msgfromClient.replyTo ; callBack.send(msgToClient);

3、测试时跨进程 android:process=":MessengerService"

 其实这里内部也是依赖一个aidl生成的类,这个aidl位于:frameworks/base/core/java/android/os/IMessenger.aidl

Server这边还使用了HandlerThread类,顺便也学习一下。

HandlerThread也是一个Thread,只不过是帮我们封装了一下Looper,注意一下使用的顺序就可以了。

创建一个HandlerThread,即创建了一个包含Looper的线程。

HandlerThread handlerThread = new HandlerThread("work-thread");

handlerThread.start(); ,创建HandlerThread后一定要记得start()(Looper的使用啥的都是在HandlerThread的run()方法里面)

获取HandlerThread的Looper   Looper looper = handlerThread.getLooper();

创建Handler,通过Looper初始化   Handler handler = new Handler(looper);

通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。

如果想让HandlerThread退出,则需要调用handlerThread.quit();。

客户端代码:

package com.example.messengerservice;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
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 android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.alibaba.fastjson.JSON;

public class MainActivity extends Activity {

private static final String TAG = "MessengerTest";
private static final int MSG_OBJ = 0x111;

private Button mBtnAdd;
private LinearLayout mLyContainer;
// 显示连接状态
private TextView mTvState;

private Messenger mService;
private boolean isConn;

private int i = 0;

// 客户端的回调,传递到服务端用于返回服务端的计算结果  Message  msgFromClient.replyTo = mMessenger;
private Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msgFromServer) {    // 接收Server端返回来的数据
switch (msgFromServer.what) {
case MSG_OBJ:
//UserInfo userInfo = (UserInfo)msgFromServer.obj;
TextView tv = (TextView) mLyContainer.findViewById(msgFromServer.arg1);
String strUserInfo = msgFromServer.getData().getString("UserInfo");
UserInfo userInfo = JSON.parseObject(strUserInfo, UserInfo.class);
tv.setText(tv.getText() + "=>" + msgFromServer.arg2 + ", userInfo = " + userInfo);
break;
}
super.handleMessage(msgFromServer);
}
});

private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);   // 和服务端的Messenger建立关联
isConn = true;
mTvState.setText("connected!");
}

@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
isConn = false;
mTvState.setText("disconnected!");
}
};

private int mA;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final UserInfo userInfo = new UserInfo();
userInfo.setAge(11);

// 开始绑定服务
bindServiceInvoked();

mTvState = (TextView) findViewById(R.id.id_tv_callback);
mBtnAdd = (Button) findViewById(R.id.id_btn_add);
mLyContainer = (LinearLayout) findViewById(R.id.id_ll_container);

mBtnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pid = android.os.Process.myPid();
Log.d(TAG, "MainActivity client pid = " + pid);
try {
int a = mA++;
int b = (int) (Math.random() * 100);

// 创建一个tv,添加到LinearLayout中
TextView tv = new TextView(MainActivity.this);
tv.setText(a + " + " + b + " = caculating ...");
tv.setId(a);
mLyContainer.addView(tv);
i ++;
userInfo.setName("name_" + i);
String strUserInfo = JSON.toJSONString(userInfo);
Log.d(TAG, "strUserInfo = " + strUserInfo);
Message msgFromClient = Message.obtain(null, MSG_OBJ, a, b);
Bundle bundle = new Bundle();  // 因为bundle实现了Parcelable接口。
bundle.putString("UserInfo", strUserInfo);
//msgFromClient.obj = strUserInfo;
msgFromClient.setData(bundle);
msgFromClient.replyTo = mMessenger;   //  设置回调
if (isConn) {
// 往服务端发送消息
mService.send(msgFromClient);
}
}
catch (RemoteException e) {
e.printStackTrace();
}
}
});

}

private void bindServiceInvoked() {
Intent intent = new Intent();
intent.setAction("com.zhy.aidl.calc");
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
Log.e(TAG, "bindService invoked !");
}

@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConn);
}
}


服务端代码:

package com.example.messengerservice;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import com.alibaba.fastjson.JSON;

public class MessengerService extends Service{
private static final String TAG = "MessengerService";
private static final int MSG_OBJ = 0x111;

private HandlerThread mHandlerThread;

private Handler mHandler;

private Messenger htMessenger;

@Override
/* mMessenger.getBinder()的实现
* public IBinder getBinder() {
return mTarget.asBinder();
}
*
* mTarget是哪来的呢? mTarget是一个MessengerImpl对象,那么asBinder实际上是返回this,也就是MessengerImpl对象;
*/
public IBinder onBind(Intent arg0) {
return htMessenger.getBinder();
}

@Override
public void onCreate() {
super.onCreate();

// 和client端的PID不一样,说明运行在不同的进程中
int pid = android.os.Process.myPid();
Log.d(TAG, "onCreate() Server pid = " + pid);

long threadId = Thread.currentThread().getId();
Log.d(TAG, "onCreate() Server threadId = " + threadId);

//生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,
//这个类由Android应用程序框架提供
mHandlerThread = new HandlerThread("work-thread");
//在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();
mHandlerThread.start();
//即这个Handler是运行在mHandlerThread这个线程中
mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msgfromClient) {
//super.handleMessage(msgfromClient);
if(msgfromClient.what != MSG_OBJ){
return;
}
sendMsgToClient(msgfromClient);
}
};

//htMessenger通过return htMessenger.getBinder()被客户端得到。
htMessenger = new Messenger(mHandler);
}

/**
*
* @param msgfromClient
*/
private void sendMsgToClient(Message msgfromClient){
Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息
//模拟耗时
try {
Thread.sleep(10000);
msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
Bundle bundle = msgfromClient.getData();
String strUserInfo = bundle.getString("UserInfo");
UserInfo userInfo = JSON.parseObject(strUserInfo, UserInfo.class);
userInfo.setAge(userInfo.getAge() + 1);
userInfo.setName(userInfo.getName() + "_from_server");
bundle.putString("UserInfo", JSON.toJSONString(userInfo));
msgToClient.setData(bundle);
// 和onCreate()中的threadId不一样,说明运行在两个不同的线程中
long threadId = Thread.currentThread().getId();
Log.d(TAG, "htMessenger Server threadId = " + threadId);

Messenger callBack = msgfromClient.replyTo; // 获得客户端的回调
callBack.send(msgToClient); // 把信息发送到客户端
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (RemoteException e) {
e.printStackTrace();
}
}
}


package com.example.messengerservice;

import android.os.Parcel;
import android.os.Parcelable;

public class UserInfo implements Parcelable{

private int age;

private String name;

/**
* @return the age
*/
public int getAge() {
return age;
}

/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}

/**
* @return the name
*/
public String getName() {
return name;
}

/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}

/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "UserInfo [age=" + age + ", name=" + name + "]";
}

@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}

@Override
public void writeToParcel(Parcel arg0, int arg1) {
}
}


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/id_ll_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
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=".MainActivity" >

<TextView
android:id="@+id/id_tv_callback"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Messenger Test!" />

<Button
android:id="@+id/id_btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add" />

</LinearLayout>


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.messengerservice"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service
android:name=".MessengerService"
android:process=":MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.zhy.aidl.calc"></action>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>

</application>

</manifest>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: