Service in Android Development

By | 2013 年 4 月 7 日

记录一下,这篇文章写得很好,很简洁,以至于我都没动力复述一遍了:
http://www.cnblogs.com/trinea/archive/2012/11/08/2699856.html

这篇文章中描述了如何创建Service,startService和bindService的区别(后者可以和Activity通讯,其实前者也行)。
针对bindService,在Service中创建一个Binder,里面可以自定义Service提供给外界的接口,在Activity调用bindService之后,在成功连接到Service的回调里面,Service提供的Binder会作为参数传给Activity。

这样,Activity就可以随心所欲操作Service了。

不过这篇文章没有回答的一个问题是:如果Service中的一些事件需要通知Activity怎么办?
这个问题我摸索了一段时间,用了好些方法来做。



第一,创建一个叫做ServiceListener的抽象类,里面定义好Service要通知Activity的函数。然后当Activity绑定到Service的时候,在Binder中提供一个注册Listener的方法(当然unregister也提供)。这样Activity可以创建一个Listener的子类来针对感兴趣的部分进行操作;而Service这边维护一个ArrayList数组,每次事件一到就通知所有的listener。

这个方法可行,不过有一个问题是,这些回调函数不一定是在主线程被调用的(因为Service经常在辅助线程干活儿)。



第二,还是沿用上面的结构,不过把Listener改为Handler,在Service这边定义好各种事件定义的Message,然后当事件发生的时候,直接向所有的Handler发送Message。由于Activity中创建的Handler都是主线程上,所以可以直接干UI的活儿。

这个方法也不错,不过损失了上一个方法中定义好的接口,没有那么方便了,开发的时候,还需要去查查Service怎么定义的各种Message,不是很方便。



第三,综合上面两种。Service还是定义一个Listener,只不过它继承自Handler,并且定义好需要通知Activity的各种接口。然后在这个基类里面,进行handleMessage()。针对每一种Message去调用对应的接口。然后Activity这边创建一个Listener的子类,重载这些接口就能干活儿了。一举两得。



—————-我是跨进程的分割线——————
不过呢,这种做法只能用于同在一个进程内的Service和Activity之间的通讯,如果Activity和Service不在一个进程的话,那就只能借助于AIDL(Android Interface Description Language)了。

在初步研究了AIDL之后,从Activity控制Service似乎是没有什么问题的(代码以后补上)。

但是AIDL并不能传送复杂数据类型,像上面方法三的办法就不能了,虽然可以在Service那边的接口中提供registerListener和unregisterListener方法,但是不能直接传送一个Handler的子类,那怎么办呢?

接着深入研究AIDL,发现虽然不能传送一个复杂数据,但是interface是可以传送的。因此我们再定义一个接口叫做IServiceListener,里面提供以简单数据作为参数的各种操作,这些操作是Service希望通知Listener的。然后在方法三的Listener中,实现这个IServiceListener的Stub类,里面针对各种调用分别向自己(Listener本身是Handler)sendMessage。而且提供一个getStubForRegister()方法返回这个Stub类就好了。这样在IService中的registerListener和unregisterListener都以这个IServiceListener为参数即可。

这样就实现了一个终极方案,不论Service在哪个进程,只需要在Activity所在进程创建一个Listener,然后重载其中的钩子函数,在Bind到Service的时候,向Service注册Listener.getStub()就可以了。Service一旦有消息要通知Listener,就会在Listener所在的线程中(一般是主线程),调用对应的钩子函数,这样就完美了。



—————-我是BUG的分割线——————
今天(20130507)遇到一个问题,bindService总返回false,也就说没有bind成功,各种测试之后发现,额,Manifest.xml中没有声明这个Service。
怎么声明呢?那就是在和activity标签并列的地方插入一段:

<service android:name="com.xxx.xxx.xxxService" />

2 thoughts on “Service in Android Development

    1. uniEagle Post author

      恩,有一个Android项目。
      也看看Android的开发怎么样。
      不过Eclipse体验真的感觉没有XCode爽。

      Reply

发表评论

电子邮件地址不会被公开。 必填项已用*标注