Android Bound Service 多线程通信

本文详细介绍了Android中Bound Service如何实现多线程通信,包括Service的配置、Messenger的使用、Activity与Service的绑定及解绑,以及如何通过Messenger发送Message。通过设置Service在不同进程中运行,避免内存泄漏,确保正确处理Activity与Service间的通信。

Service 部分

首先,新建一个Service,要让这个Service跟UI运行在两个不同的进程上,只需在manifests里添加上Service的android:process属性(进程名字而已,没有什么要求)。

<service
        android:name=".MyService"
        android:enabled="true"
        android:exported="false"
        android:process="ProcessName">
</service>

进程间通信是通过Message进行的,而Massage由Messenger转发和接受,所以我们要在通信两端各写一个Messenger

//send message to the IncomingHandler
   final Messenger mMessenger = 
       new Messenger(new IncomingHandler());

这样一来,接到的消息都会通过IncommingHandler处理,至于收到Message后具体怎么处理,就跟你在IncommingHandler里面是怎么重载 handleMessage()有关了,这是一个例子:

//send message to the IncomingHandler
final Messenger mMessenger = new Messenger(new IncomingHandler());

private class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 0:
                Log.d("TAG","receive message 0");
                break;
            case 1:
                Log.d("TAG","receive message 1");
                break;
            default:
                super.handleMessage(msg);
        }
    }
}

注意,如果Handler中包含对Service或Activity其他成员或函数的引用,那么将影响到Service或Activity被回收,可能导致内存泄露。正确的做法是用WeakReference

最后,在Service中重载回调函数onBind(),每次被一个Activity绑定的时候,这个函数会被调用。

/*  When clients binding to the service, we return an interface to our messenger for sending messages to the service.*/
 @Override
 public IBinder onBind(Intent intent) {
     return mMessenger.getBinder();
 }

Activity部分

前面说了,Messenger是负责转发Message, Activity与Service之间的通信通过Message进行,Service部分的Messenger大家应该都懂是怎么一回事了吧?可能我没有说清楚,十分欢迎留言或发邮件给我。现在介绍Activity部分。其实两边的写法都差不多,前面看懂了,后面就比较简单了。

首先,同样的在Activity里定义一个接收Message的Messenger,和一个处理接收到的Message的Handler。

//send message to the IncomingHandler
   final Messenger mMessenger = new Messenger(new IncomingHandler());

要绑定Activity与Service,只需在onCreate()或者其他需要的位置调用bindService()函数就好了,需要传入的参数是:
1. Intent,就像跳转到其他的Activity一样写跳转到Service的Intent
2. ServiceConnection,马上就要将这部分了
3. 绑定的模式,一个常量,定义在Context里。

bindService(new Intent(this, MyService.class), 
                mConnection, Context.BIND_AUTO_CREATE);

其中mConnection是连接Service重要的参数,接下来介绍怎么写。
新建一个ServiceConnection类,重载两个函数onServiceConnectedonServiceDisconnected,这两个函数分别会在服务连接上和服务断开时被调用,直接上代码:

// Msg.java

// 定义消息名称
public static final int MSG_REGISTER = 0;

// 定义MSG_REGISTER的参数1可选值:
// Activity的代号,以区分绑定的Activity
public static final int ACTIVITY_MAIN = 1;
//...


// MainActivity.java
ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
          // 从Ibinder获取在Service那边传入的Messenger
            mServiceMessenger = new Messenger(service);
            mBounded = true;
            // try块只是为了告诉Service“是我连上你的服务了!”
            try {
                //首先创建一个消息,为了避免重复创建,更好利用消息池,
                //使用Message.obtain来创建。
                //Msg.MSG_REGISTER是自己定义的一个整数,
                //表示这个消息的内容是:注册(绑定)一个新的Activity
                Message msg = Message.obtain(null, Msg.MSG_REGISTER);
                msg.replyTo = mServiceMessenger;
                msg.arg1 = Msg.ACTIVITY_MAIN;
                mServiceMessenger.send(msg);
            } catch (RemoteException e) {
                Log.e("TAG","无法绑定服务");
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name){
            mServiceMessenger = null;
            mBounded = false;
        }
    };

至此,绑定的工作就已经全部介绍完毕了。

解除绑定

在Activity销毁的时候,我们一般希望显示的解绑,并在Service上做一些动作。

 public void UnbindService(){
        if (mBounded) {
            getApplicationContext().
                    unbindService(mConnection);
            mBounded = false;
        }
    }

用Messenger发送Message

以上两部分已经分别讲解了Service里和Activity里应该怎么写Messenger来接收消息,这部分将说明怎样用Messenger发送Message给对方。
方法很简单,

  mMessenger.send(msg);

如果考虑得更细致一些,会在调用send()函数前先检测一下连接,检查一下mBounded是否为true,否则尝试重新绑定服务,像我这样,封装成一个函数:

public void sendToService(Message msg) {
      if (mBounded && mMessenger != null) {
          try {
              mMessenger.send(msg);
              Log.v(TAG, " sent " + msg.what);
          } catch (RemoteException e) {
              Log.e(TAG, e.toString());
              BindService();
          }
      } else {
          BindService();
          Log.e(TAG, "mMessenger is null or Service unbounded");
      }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值