为了账号安全,请及时绑定邮箱和手机立即绑定

Android Service实现双向通信(一)

标签:
Android

首先,大概来总结一下与Service的通信方式有很多种:

  1. 通过BroadCastReceiver:这种方式是最简单的,只能用来交换简单的数据;

  2. 通过Messager:这种方式是通过一个传递一个Messager给对方,通过这个它来发送Message对象。这种方式只能单向传递数据。可以是ServiceActivity,也可以是从Activity发送数据给Service。一个Messeger不能同时双向发送;

  3. 通过Binder来实现远程调用(IPC):这种方式是Android的最大特色之一,让你调用远程Service的接口,就像调用本地对象一样,实现非常灵活,写起来也相对复杂。

本文最重点谈一下怎么使用AIDL实现Service端和Client端的双向通信(或者叫"调用")。

首先定义一个AIDL接口如下:

// IRemoteService.aidlpackage com.race604.servicelib;interface IRemoteService {  
    int someOperate(int a, int b);}

这里只定义了一个简单的接口someOperate(),输入参数ab,返回一个int值。

Service的实现如下:

// RemoteService.javapackage com.race604.remoteservice;import ...public class RemoteService extends Service {  
    private static final String TAG = RemoteService.class.getSimpleName();
    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        @Override        public int someOperate(int a, int b) throws RemoteException {
            Log.d(TAG, "called RemoteService someOperate()");
            return a + b;
        }
    };

    @Override    public IBinder onBind(Intent intent) {
        return mBinder; // 注意这里返回binder    }}

这里,在RemoteService里面实现一个IRemoteService.Stub接口的Binder,并且在onBind()中返回此Binder对象。 在AndroidManifest.xmlRemoteService的申明如下:

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

  <intent-filter>
      <action android:name="com.race604.servicelib.IRemoteService" />
  </intent-filter></service>

这里android:exported="true"表示可以让其他进程绑定,这里还有一个<action android:name="com.race604.servicelib.IRemoteService" />,这里是为了让后面的Client通过此Action来绑定。

Client的调用方法如下:

package com.race604.client;import ...public class MainActivity extends ActionBarActivity implements View.OnClickListener {

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

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override        public void onServiceConnected(ComponentName name, IBinder service) {
            Toast.makeText(MainActivity.this, "Service connected", Toast.LENGTH_SHORT).show();
            mService = IRemoteService.Stub.asInterface(service);
        }

        @Override        public void onServiceDisconnected(ComponentName name) {
            Toast.makeText(MainActivity.this, "Service disconnected", Toast.LENGTH_SHORT).show();
            mService = null;
        }
    };

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

        findViewById(R.id.bind).setOnClickListener(this);
        findViewById(R.id.unbind).setOnClickListener(this);
        findViewById(R.id.call).setOnClickListener(this);
    }

    private void callRemote() {

        if (mService != null) {
            try {
                int result = mService.someOperate(1, 2);
                Toast.makeText(this, "Remote call return: " + result, Toast.LENGTH_SHORT).show();
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "Remote call error!", Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(this, "Service is not available yet!", Toast.LENGTH_SHORT).show();
        }
    }

    @Override    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bind:
                Intent intent = new Intent(IRemoteService.class.getName());
                bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
                break;
            case R.id.unbind:
                unbindService(mServiceConnection);
                break;
            case R.id.call:
                callRemote();
                break;
        }
    }}

在客户端,使用Context.bindService()函数,绑定到远程的Service。注意到这里的Intent intent = new Intent(IRemoteService.class.getName());,和上面的Service申明的Action一致。BIND_AUTO_CREATE这个Flag从名字就能看出,表示如果Bind的时候,如果还没有Service的实例,就自动创建。
这里有一个地方需要注意,在Android 5.0以后,就不允许使用非特定的Intent来绑定Service了,需要使用如下方法:

Intent intent = new Intent(IRemoteService.class.getName());  intent.setClassName("com.race604.remoteservice", "com.race604.remoteservice.RemoteService");  // 或者setPackage()// intent.setPackage("com.race604.remoteservice");bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

到这里就基本实现了一个完整的Client调用远程Service的实例了。

源代码可以参考这个Commit

原文链接:http://www.apkbus.com/blog-705730-61301.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消