Messenger——比AIDL简单的跨进程通讯

Messenger

标签: 跨进程通讯


参考Blog

目录


在日常开发中,很少遇到跨进程通讯的需求。所以跨进程通讯这一块一直是我的痛点,准备面试的过程中,又一次揭开伤疤,痛定思痛,终于下定决心解决这一盲区。
我们在学习中,经常说到跨进程通讯,立马想起AIDL,在上一篇Blog中对AIDL以及定向tag做了还算详细的整理,如果有兴趣可以复习一下 学习AIDL,这一篇差不多了

首先

无耻的引入一下 lypeer的博文:

大家看到Messenger可能会很轻易的联想到Message,然后很自然的进一步联想到Handler——没错,Messenger的核心其实就是Message以及Handler来进行线程间的通信。下面讲一下通过这种方式实现IPC的步骤:

  • 服务端实现一个Handler,由其接受来自客户端的每个调用的回调
  • 使用实现的Handler创建Messenger对象
  • 通过Messenger得到一个IBinder对象,并将其通过onBind()返回给客户端
  • 客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务
  • 服务端在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message

1. 服务端配置

1.1 实现Handler

实现Handler不需要多说,在没有RxJava的日子里,不知道写过多少遍,直接上代码:

@SuppressLint("HandlerLeak")
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    Toast.makeText(MessagerService.this, "发送的信息是 0", Toast.LENGTH_SHORT).show();
                    break;
                case 1:
                    Bundle data = msg.getData();
                    String str = data.getString("data");
                    Toast.makeText(MessagerService.this, "收到的消息是 1 : " + str, Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };

1.2 创建Messenger

final Messenger messenger = new Messenger(handler);

1.3 设置onBind()方法返回值

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

1.4 服务端整体代码

public class MessagerService extends Service {

    public MessagerService() {
    }

    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    Toast.makeText(MessagerService.this, "发送的信息是 0", Toast.LENGTH_SHORT).show();
                    Log.e(TAG, "handleMessage: 发送的信息是 0");
                    break;
                case 1:
                    Bundle data = msg.getData();
                    String str = data.getString("data");
                    Toast.makeText(MessagerService.this, "收到的消息是 1 : " + str, Toast.LENGTH_SHORT).show();
                     Log.e(TAG, "handleMessage:  收到的消息是 1 :  " + str);
                    break;
            }
        }
    };

    final Messenger messenger = new Messenger(handler);

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

}

1.6 配置

想要跨进程调用Service,需要在AndroidManifest.xml进行配置:

        <service
            android:name=".MessagerService"
            android:enabled="true"
            android:exported="true">

            <intent-filter>
                <action android:name="com.martin.messagerserver" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

        </service>

2. 客户端实现

2.1 绑定服务

private void connectService() {
        Intent intent = new Intent()
                .setAction("com.martin.messagerserver")
                .setPackage("com.martin.messagerserver");
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnect = true;
            messenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isConnect = false;
        }
    };

2.2 设置点击事件

public void sendZero(View view) {
        if (isConnect && messenger != null) {
            Message msg = Message.obtain();
            msg.what = 0;
            try {
                messenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "0 发送失败了", Toast.LENGTH_SHORT).show();
                Log.e(TAG, "sendZero: 0 发送失败了");
            }
        } else {
            Toast.makeText(this, "0 并没有连接上", Toast.LENGTH_SHORT).show();
            Log.e(TAG, "sendZero: 0 并没有连接上");
        }
    }

    public void sendOne(View view) {
        if (isConnect && messenger != null) {
            Message obtain = Message.obtain();
            obtain.what = 1;
            Bundle data = new Bundle();
            data.putString("data", "我是从客户端发过来的哟!再次测试");
            obtain.setData(data);
            try {
                messenger.send(obtain);
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "1 发送失败咯", Toast.LENGTH_SHORT).show();
                Log.e(TAG, "sendOne: 1 发送失败咯");
            }
        } else {
            Toast.makeText(this, "1 未连接", Toast.LENGTH_SHORT).show();
            Log.e(TAG, "sendOne: 1 未连接");
        }
    }

2.3 客户端全代码

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    private boolean isConnect = false;
    private Messenger messenger;

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

    public void sendZero(View view) {
        if (isConnect && messenger != null) {
            Message msg = Message.obtain();
            msg.what = 0;
            try {
                messenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "0 发送失败了", Toast.LENGTH_SHORT).show();
                Log.e(TAG, "sendZero: 0 发送失败了");
            }
        } else {
            Toast.makeText(this, "0 并没有连接上", Toast.LENGTH_SHORT).show();
            Log.e(TAG, "sendZero: 0 并没有连接上");
        }
    }

    public void sendOne(View view) {
        if (isConnect && messenger != null) {
            Message obtain = Message.obtain();
            obtain.what = 1;
            Bundle data = new Bundle();
            data.putString("data", "我是从客户端发过来的哟!再次测试");
            obtain.setData(data);
            try {
                messenger.send(obtain);
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "1 发送失败咯", Toast.LENGTH_SHORT).show();
                Log.e(TAG, "sendOne: 1 发送失败咯");
            }
        } else {
            Toast.makeText(this, "1 未连接", Toast.LENGTH_SHORT).show();
            Log.e(TAG, "sendOne: 1 未连接");
        }
    }


    @Override
    protected void onStart() {
        super.onStart();
        connectService();
    }

    /**
     * 连接服务
     */
    private void connectService() {
        Intent intent = new Intent()
                .setAction("com.martin.messagerserver")
                .setPackage("com.martin.messagerserver");
        bindService(intent, connection, BIND_AUTO_CREATE);
    }


    @Override
    protected void onStop() {
        super.onStop();
        // 解绑 service
        unbindService(connection);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnect = true;
            messenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isConnect = false;
        }
    };

}

总结

貌似也没讲解什么,就是贴了代码。
算了,直接贴源码吧,CSDN源码最低设置2分,如果有需要可以留下邮箱,我看到会即使回的。

源码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值