Android开发艺术探索2-进程通信(Messenger)

650 阅读9分钟

我们先把通信机制图 画出来,然后再贴具体实现代码

 

下面,我们先看服务端代 码:

我们需要一个背后运行的service来 为其他应用提供工作,所以很快的我们就想到了 创建一个类继承Service,并实现其onBind(Intentintent)方法

public IBinderonBind (Intent intent) {    returnnull; }

很明显,这里需要我 们返回一个IBinder的接口或者实现类,而这里我们的Message.getBinder()可以提供;所以需要我们创建Message对象;我们继续看Message的构造函数:

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

需要一个handler处理器,那我们 就自己创建一个handler对象咯; 为了避免内存泄露,我们常创 建一个静态Handler类:

private static class MessengerHandler extends Handler {    @Override    public void handleMessage(Message msg) {          super.handleMessage(msg);     }}

其handlerMessage(Message msg)方法内部就进行接收到的数据处理。

 

完整的service代码:

public class MessengerService extends Service {    private static final String TAG = "MessengerService";    private Messenger mClientMessenger;    private static class MessengerHandler extends Handler {        @Override        public void handleMessage(Message msg) {            Log.d(TAG, "YYYYYYYYYY");            switch (msg.what) {                case IPCContants.MSG_FROM_CLIENT:                    Object object = msg.obj;                    if (!(object instanceof Bundle)){                        break;                    }                    Bundle bundle = (Bundle) object;                    String clientMsg = bundle.getString("client");                    Log.d(TAG, "YYYYYYYYYY receive msg from client: " + clientMsg);                    replayClient(msg);                    break;                default:                    super.handleMessage(msg);                    break;            }        }    }    private static void replayClient(Message msg) {        Messenger serviceMessage = msg.replyTo;        Message message = new Message();        Bundle bundle = new Bundle();        bundle.putString("service", "hi, this is service msg");        message.obj = bundle;        message.what = IPCContants.MSG_FROM_SERVICE;        try {            serviceMessage.send(message);        } catch (RemoteException e) {            e.printStackTrace();        }    }    @Nullable    @Override    public IBinder onBind(Intent intent) {        MessengerHandler messengerHandler = new MessengerHandler();        mClientMessenger = new Messenger(messengerHandler);        Log.d(TAG, "service is connection ...");        return mClientMessenger.getBinder();    }    @Override    public void onDestroy() {        super.onDestroy();    }}

 

好、现在服务端代码写完了,但别忘了、我们需要把service给暴露外面应用调用,所以需要在manifest中进行配置,export=true 为允许其他应用调用;<intent-filter>为隐私启动的过滤配置

 

完整配置:

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

 

好了、现在我们来看客户端代码

客户需要主动调用,所以我们最平常的就是写acitivity然后放一个按钮,点击按钮进行与服务端的数据通信;当然最重要的事就是我们要与服务端的service进行建立连接才行啊,怎么连接呢?

我们刚看到服务端是通过service来提供服务的,所以我们要进行连接,就是启动服务端的service方法;所以用隐私启动来调用:

Intent intent = new Intent();intent.setComponent(new ComponentName("com.example.hfs.alipayuidemo","com.example.hfs.alipayuidemo.ipcService.MessengerService"));bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

 

注意、这里有个坑:就是安卓5.0以后需要用查询匹配的方式进行启动、具体添加下面的方法:

public Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {    // Retrieve all services that can match the given intent    PackageManager pm = context.getPackageManager();    List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);    // Make sure only one match was found    if (resolveInfo == null || resolveInfo.size() != 1) {        return null;    }    // Get component info and create ComponentName    ResolveInfo serviceInfo = resolveInfo.get(0);    String packageName = serviceInfo.serviceInfo.packageName;    String className = serviceInfo.serviceInfo.name;    ComponentName component = new ComponentName(packageName, className);    // Create a new intent. Use the old one for extras and such reuse    Intent explicitIntent = new Intent(implicitIntent);    // Set the component to be explicit    explicitIntent.setComponent(component);    return explicitIntent;}

 

我们上面进行启动service时,有个mConnection参数,这个参数是干啥的呢?很明显、我们进行连接,需要一个serviceConnection对象;所以我们提前实例化此接口,暴露两方法:连接成功或失败

@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {
}@Overridepublic void onServiceDisconnected(ComponentName name) {}

看到没,连接成功给我们返回了IBinder接口,前面我们写服务端时,连接成功在onBind()方法中,返回的就是这个IBinder接口;所以,我们现在只需要拿到这个IBinder接口来传输数据就可以了,这里我们先拿一个Messenger对象来存储:

mServiceMessenger = new Messenger(service);

 

好了 ,现在我们通过按钮来主动发送消息给服务端了:

先构造一个Message对象,然后把想传输的数据封装好放上面;再用之前保留的建立连接的Messenger来进行发送;

try {    Message clientMessage = new Message();    clientMessage.what = IPCContants.MSG_FROM_CLIENT;    Bundle clientBundle = new Bundle();//进程之间传递非基本数据类型的数据,需要使用Bundle,因为它实现了Parcelable    clientBundle.putString("client","Hello,I am client user!");    clientMessage.obj = clientBundle;    mServiceMessenger.send(clientMessage);} catch (RemoteException e) {    e.printStackTrace();}

当然了,如果你想接受服务端的返回数据并进行处理,那同样的、我们需要创建一个Handler,然后用Messenger对象来包装好,并在发送消息时把自己作为回应给赋值上

clientMessage.replyTo = mClientMessenger;

 

回看服务端代码,我们可以发现、服务端进行回应数据的发送就是客户端这里创建好的Messenger对象:

MessengerHandler clientMessengerHandler = new MessengerHandler();mClientMessenger = new Messenger(clientMessengerHandler);

 

客户端完整代码:

public class MessengerActivity extends BaseActivity {    private static final String TAG = "MessengerActivity";    private Messenger mServiceMessenger;    private Messenger mClientMessenger;    private static class MessengerHandler extends Handler {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case IPCContants.MSG_FROM_SERVER:                    Object object = msg.obj;                    if (!(object instanceof Bundle)){                        break;                    }                    Bundle bundle = (Bundle) object;                    String serviceMsg = bundle.getString("service");                    LogUtil.d(TAG, "receive msg from service: " + serviceMsg);                    break;                default:                    super.handleMessage(msg);                    break;            }        }    }    private ServiceConnection mConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            LogUtil.d(TAG, "service is connection ...");            mServiceMessenger = new Messenger(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };    @Override    protected int layoutId() {        return R.layout.activity_download;    }    @Override    protected void initView() {        super.initView();        Button button = (Button)findViewById(R.id.btn_download);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                clientSendMSg();            }        });    }    @Override    protected void doOtherThing() {        super.doOtherThing();        connectService();    }    protected void connectService() {        Intent intent = new Intent();        intent.setComponent(new ComponentName("com.example.hfs.alipayuidemo","com.example.hfs.alipayuidemo.ipcService.MessengerService"));        intent = createExplicitFromImplicitIntent(this, intent);        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);        MessengerHandler clientMessengerHandler = new MessengerHandler();        mClientMessenger = new Messenger(clientMessengerHandler);    }    private void clientSendMSg(){        try {            Message clientMessage = new Message();            clientMessage.what = IPCContants.MSG_FROM_CLIENT;            Bundle clientBundle = new Bundle();//进程之间传递非基本数据类型的数据,需要使用Bundle,因为它实现了Parcelable            clientBundle.putString("client","Hello,I am client user!");            clientMessage.obj = clientBundle;            clientMessage.replyTo = mClientMessenger;//通过clientMessage消息对象把客户端信使传递给服务端            mServiceMessenger.send(clientMessage);        } catch (RemoteException e) {            e.printStackTrace();        }    }    public Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {        // Retrieve all services that can match the given intent        PackageManager pm = context.getPackageManager();        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);        // Make sure only one match was found        if (resolveInfo == null || resolveInfo.size() != 1) {            return null;        }        // Get component info and create ComponentName        ResolveInfo serviceInfo = resolveInfo.get(0);        String packageName = serviceInfo.serviceInfo.packageName;        String className = serviceInfo.serviceInfo.name;        ComponentName component = new ComponentName(packageName, className);        // Create a new intent. Use the old one for extras and such reuse        Intent explicitIntent = new Intent(implicitIntent);        // Set the component to be explicit        explicitIntent.setComponent(component);        return explicitIntent;    }    @Override    protected void onDestroy() {        unbindService(mConnection);        super.onDestroy();    }}

 

具体代码,可以到github下载:https://github.com/guiyichen/demoGavin