Android中的Messenger的原理及基本用法

这边博客主要记录一下Android中Messenger的基本原理和用法。


简单来讲,Messenger其实就是Binder通信的包装器,是一种基于消息传递的进程间通信工具。

//Messenger实现了Parcelable接口,因此可以跨进程传输
public final class Messenger implements Parcelable {
    ...............
}

通常情况下,我们可以在A进程中创建一个Messenger,然后将该Messenger传递给B进程。
于是,B进程就可以通过Messenger与A进程通信了。


Messenger通常与Handler一起使用,我们看看对应的源码:

public final class Messenger implements Parcelable {
    private final IMessenger mTarget;

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

跟进一下Handler的getIMessenger函数:

    .............
    final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            //返回的是Handler中定义的MessengerImpl
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

    //此处MessengerImpl继承自IMessenger.Stub
    //容易看出MessengerImpl将作为Binder通信的接收端
    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

从上述代码可以看出,Messenger实际上作为了一个Binder服务端的wrapper。


当我们在A进程中创建Messenger,然后传递给B进程时,Messenger需要执行Parcelable接口定义的操作,于是:

    //在A进程中将Binder信息写入到Parcel中
    public void writeToParcel(Parcel out, int flags) {
        out.writeStrongBinder(mTarget.asBinder());
    }

    public static final Parcelable.Creator<Messenger> CREATOR
            = new Parcelable.Creator<Messenger>() {
        //在B进程中,重新创建Binder
        public Messenger createFromParcel(Parcel in) {
            IBinder target = in.readStrongBinder();

            //调用Messenger的另一个构造函数
            return target != null ? new Messenger(target) : null;
        }

        public Messenger[] newArray(int size) {
            return new Messenger[size];
        }
    };

跟进一下Messenger的另一个构造函数:

public Messenger(IBinder target) {
    //得到的是Binder通信的客户端
    mTarget = IMessenger.Stub.asInterface(target);
}

因此,当Messenger从进程A传递到进程B时,它就变为了Binder通信客户端的wrapper。


当在进程B中使用Messenger的接口时:

public void send(Message message) throws RemoteException {
    //mTarget为Binder通信的客户端,将消息发送给服务端的send函数
    //即服务端Handler的MessengerImpl的send函数
    //上文已经附上了对应代码,可以看到对应的消息将递交给Handler处理
    mTarget.send(message);
}

以上就是Messenger通信的原理,现在实际测试一下。
我们定义一个简单的demo,包含一个Activity和一个Service,其中Service与Activity处在不同的进程中。

AndroidManifest.xml中的定义如下:

        .....................
        <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=".RemoteService"
            android:enabled="true"
            android:exported="true"
            <!--指定服务运行在其它进程-->
            android:process=".remote">
        </service>
        ..............

Activity的界面很简单,当点击时就会像Service发送消息,Activity代码如下:

public class MainActivity extends AppCompatActivity {
    private Button mButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //打印Activity的pid及所在进程名称
        Log.d("ZJTest", "Activity, pid: " + Process.myPid() +
                ", name: " + Util.getProcessName(this));

        //启动服务
        startService();

        //绑定服务
        bindService();

        mButton = (Button) findViewById(R.id.test_button);
        mButton.setEnabled(false);
        //点击按键后,利用Messenger向Service发送消息
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mMessenger != null) {
                    try {
                        Message msg = Message.obtain();
                        msg.what = 1;
                        mMessenger.send(msg);
                    } catch (RemoteException e) {
                        Log.d("ZJTest", e.toString());
                    }
                }
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unBindService();
        stopService();
    }

    private Intent mIntent;
    private void startService() {
        mIntent = new Intent(this, RemoteService.class);
        this.startService(mIntent);
    }

    private ServiceConnection mServiceConnection;
    private void bindService() {
        mServiceConnection = new LocalServiceConnection();
        this.bindService(mIntent, mServiceConnection, BIND_AUTO_CREATE);
    }

    Messenger mMessenger;
    private class LocalServiceConnection implements android.content.ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //绑定服务后,获得Messenger并激活Button
            mMessenger = new Messenger(service);
            mButton.setEnabled(true);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mButton.setEnabled(false);
        }
    }

    private void stopService() {
        stopService(mIntent);
    }

    private void unBindService() {
        unbindService(mServiceConnection);
    }
}

Service对应的代码如下:

public class RemoteService extends Service {
    private Messenger mMessenger;

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

        //同样打印进程号及名称
        Log.d("ZJTest", "Service, pid: " + Process.myPid()
                + ", name: " + Util.getProcessName(this));

        LocalHandler mHandler = new LocalHandler();

        mMessenger = new Messenger(mHandler);
    }

    private static class  LocalHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            Log.d("ZJTest", "receive msg: " + msg.what);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        //被绑定时,返回Messenger
        return mMessenger.getBinder();
    }
}

获取进程名的代码如下:

class Util {
    static String getProcessName(Context context) {
        int pid = Process.myPid();
        ActivityManager am = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);

        for (ActivityManager.RunningAppProcessInfo appProcessInfo:
                am.getRunningAppProcesses()) {
            if (appProcessInfo.pid == pid) {
                return appProcessInfo.processName;
            }
        }

        return null;
    }
}

上述代码都是比较简单的,现在来看看运行结果:

02-20 21:25:15.760 D/ZJTest  (30460): Activity, pid: 30460, name: stark.a.is.zhang.messengertest
02-20 21:25:15.769 D/ZJTest  (30428): Service, pid: 30428, name: .remote
02-20 21:25:32.111 D/ZJTest  (30428): receive msg: 1

从log可以看出,Activity与Servie运行在不同的进程中,Messenger确实可以在不同进程间传递消息。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值