Android 基于Message的进程间通信

Android 基于Message的进程间通信

注:参考链接 https://blog.csdn.net/lmj623565791/article/details/47017485

通过两个apk演示,一个apk是Server端,一个是Client端;

服务端

package com.example.messengerservice;

import android.app.Service;
import android.content.Intent;
import android.os.Build;
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;

public class MessengerService extends Service {


    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

    private static final int MSG_SUM = 0x110;

    //最好换成HandlerThread的形式
    private Messenger mMessenger = new Messenger(new Handler()
    {
        @Override
        public void handleMessage(Message msgfromClient)
        {
            Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息

            Bundle bundle2=msgToClient.getData();//获取Bundle对象
            switch (msgfromClient.what)
            {
                //msg 客户端传来的消息
                case MSG_SUM:
                    msgToClient.what = MSG_SUM;
                    try
                    {
                        //模拟耗时
                        Thread.sleep(2000);
//                        msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
                        Bundle bundle=new Bundle();
                        bundle.putString("name",bundle2.getString("name"));
                        bundle.putString("sex",bundle2.getString("sex"));
                        Message message=new Message();
                        message.setData(bundle);
                        message.what=MSG_SUM;
                        msgfromClient.replyTo.send(message);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    } catch (RemoteException e)
                    {
                        e.printStackTrace();
                    }
                    break;
            }

            super.handleMessage(msgfromClient);
        }
    });

}

服务端别忘了注册服务

  <service
            android:name=".MessengerService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.messengerservice"></action>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

客户端

package com.example.viewcirclebar;


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.LinearLayout;
import android.widget.TextView;



public class MainActivity extends AppCompatActivity {
    private TextView tv;
    private static final String TAG = "MainActivity";
    private static final int MSG_SUM = 0x110;
    private LinearLayout mLayout;

    private Messenger messenger=new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_SUM:
                    Bundle bundle2=msg.getData();
//                    TextView tv = (TextView) mLayout.findViewById(msg.what);
//                    tv.setText(tv.getText() + "=>" + msg.arg2);
                    mTvState.setText(bundle2.getString("name")+"==="+bundle2.getString("sex"));
                    break;
            }
        }
    });
    //显示连接状态
    private TextView mTvState;

    private Messenger mService;
    private boolean isConn;
    private int mA;
    private ServiceConnection mConn = new ServiceConnection()
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            mService = new Messenger(service);
            isConn = true;
            mTvState.setText("connected!");
        }

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTvState=findViewById(R.id.tv);
        bindServiceInvoked();
        Button button= findViewById(R.id.button);
        mLayout=findViewById(R.id.mLayout);
        button.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                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);
//                    mLayout.addView(tv);



//                    Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);
                    Bundle bundle=new Bundle();
                    bundle.putString("name","only");
                    bundle.putString("sex","男");
                    Message message=new Message();
                    message.setData(bundle);
                    message.what=MSG_SUM;
                    Message msgFromClient = Message.obtain(message);
                    msgFromClient.replyTo = messenger;
                    if (isConn)
                    {
                        //往服务端发送消息
                        mService.send(msgFromClient);
                    }
                } catch (RemoteException e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
    private void bindServiceInvoked()
    {
        Intent intent = new Intent();
        intent.setPackage("com.example.messengerservice");
        intent.setAction("com.example.messengerservice");
        bindService(intent, mConn, Context.BIND_AUTO_CREATE);
        Log.e(TAG, "bindService invoked !");
    }
    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        unbindService(mConn);
    }
}

xml布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity"
    android:id="@+id/mLayout"
    android:animateLayoutChanges="true">
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="123"
        android:textSize="20dp"/>


</LinearLayout>

代码就这样了,看一下服务端代码


    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

服务端中onBind(Intent intent)方法中的返回,这里通过getBinder()返回的IBinder,点击进去看到

  public IBinder getBinder() {
        return mTarget.asBinder();
    }

可以看到返回的是mTarget.asBinder();
mTarget是哪来的呢?
我们前面去构造mMessenger对象的代码:new Messenger(new Handler());点击Messenger

  public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

可以看到mTarget是Handler返回出来的,在点击看getIMessenger(),如何点击不了的我们可以点击Handler在其中全局查找到getIMessenger();

  final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

这里看到mTarget是MessengerImpl()的一个对象,那么asBinder实际上是返回this,也就是MessengerImpl对象;
这是个内部类,可以看到继承自IMessenger.Stub,然后实现了一个send方法,该方法就是将接收到的消息通过 Handler.this.sendMessage(msg);发送到handleMessage方法。

这里可以看出我们传统写aidl文件有点一样,aapt给我们生成什么,生成IXXX.Stub类,然后我们服务端继承IXXX.Stub实现接口中的方法。

package android.os;  

import android.os.Message;  

/** @hide */  
oneway interface IMessenger {  
    void send(in Message msg);  
}  

看到这,你应该明白了,Messenger并没有什么神奇之处,实际上,就是依赖该aidl文件生成的类,继承了IMessenger.Stub类,实现了send方法,send方法中参数会通过客户端传递过来,最终发送给handler进行处理。

客户端代码

客户端首先通过onServiceConnected拿到sevice(Ibinder)对象

 private ServiceConnection mConn = new ServiceConnection()
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            mService = new Messenger(service);
            isConn = true;
            mTvState.setText("connected!");
        }

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

而,我们的代码中是

mService = new Messenger(service);

跟进去,你会发现:

 public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

客户端与服务端通信,实际上和我们平时的写法没有任何区别,通过编写aidl文件,服务端onBind利用Stub编写接口实现返回;客户端利用回调得到的IBinder对象

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

这里提一下,这里如何没有设置setPackage()方法的话会报错java.lang.IllegalArgumentException: Service Intent must be explicit: Intent,而之前的参考链接没有的。

这是我往服务器端发送的数据

Bundle bundle=new Bundle();
                    bundle.putString("name","only");
                    bundle.putString("sex","男");
                    Message message=new Message();
                    message.setData(bundle);
                    message.what=MSG_SUM;
                    Message msgFromClient = Message.obtain(message);
                    msgFromClient.replyTo = messenger;

我们看一下 Message.obtain(message)

public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        m.sendingUid = orig.sendingUid;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;

        return m;
    }

看到这,知道我们实际可以通过我们常用的Message 传参,其实我们只要稍加修改就能传递其他的参数类型,可以多看下其他obtain()的方法

服务端与客户端通信

那么,客户端与服务端通信的确没什么特殊的地方,我们完全也可以编写个类似的aidl文件实现;那么服务端是如何与客户端通信的呢?

还记得,客户端send方法发送的是一个Message,这个Message.replyTo指向的是一个mMessenger,我们在Activity中初始化的。

那么将消息发送到服务端,肯定是通过序列化与反序列化拿到Message对象,我们看下Message的反序列化的代码:

private void readFromParcel(Parcel source) {
        what = source.readInt();
        arg1 = source.readInt();
        arg2 = source.readInt();
        if (source.readInt() != 0) {
            obj = source.readParcelable(getClass().getClassLoader());
        }
        when = source.readLong();
        data = source.readBundle();
        replyTo = Messenger.readMessengerOrNullFromParcel(source);
        sendingUid = source.readInt();
    }

主要看replyTo,调用的是Messenger.readMessengerOrNullFromParcel

public static Messenger readMessengerOrNullFromParcel(Parcel in) {
        IBinder b = in.readStrongBinder();
        return b != null ? new Messenger(b) : null;
    }

    public static void writeMessengerOrNullToParcel(Messenger messenger,
            Parcel out) {
        out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
                : null);
    }

通过上面的writeMessengerOrNullToParcel可以看到,它将客户端的messenger.mTarget.asBinder()对象进行了恢复,客户端的message.mTarget.asBinder()是什么?

客户端也是通过Handler创建的Messenger,于是asBinder返回的是:

public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
 final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

   public IBinder getBinder() {
        return mTarget.asBinder();
    }

那么asBinder,实际上就是MessengerImpl extends IMessenger.Stub中的asBinder了。

#IMessenger.Stub

@Override 
public android.os.IBinder asBinder()
{
return this;
}

其实返回的就是MessengerImpl对象自己。到这里可以看到message.mTarget.asBinder()其实返回的是客户端的MessengerImpl对象。

最终,发送给客户端的代码是这么写的:

msgfromClient.replyTo.send(msgToClient);

public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

这个mTarget实际上就是对客户端的MessengerImpl对象的封装,那么send(message)(屏蔽了transact/onTransact的细节),这个message最终肯定传到客户端的handler的handleMessage方法中。

在这里插入图片描述

注:转载链接 https://blog.csdn.net/lmj623565791/article/details/47017485

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值