IPC跨进程交互(1)Messenger的使用

本文详细介绍了一个简单的Messenger跨进程通信(IPC)示例,包括服务端Service和客户端Client的实现过程,涉及Messenger对象的构建、Handler的使用及AndroidManifest.xml配置等关键技术点。

前段时间看着网上的一些文章,算是稍微学了点跨进程交互。虽然实现了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

我们就是通过这两个参数来实现隐式开启别的项目的服务的。


代码讲解块就这样讲完了。

我们来看下结果吧!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值