四大组件之Service(1)-双子座的Service-Start Service与Bind Service
第1节 Service介绍
Service
是安卓系统的四大组件之一。如果说Activity
是专门为用户“看”的系统组件,那Service
就是隐藏在角落默默付出的系统组件。
最典型的例子就是音乐播放器。音乐播放器应用中,播放音乐的组件就是一个Service
。音乐播放器的界面就是一个提供了音乐控制方式的Activity
,当我们点击Activity
上的播放按钮之后,Activity
通知播放器的Service
组件,让Service
组件开始播放音乐;之后即使用户选择退出了音乐播放器的Activity
界面,音乐仍然在被播放着,并没有随着界面的退出而停止播放。
一个应用要拥有与用户交互的界面,它就要使用Activity
组件;一个应用不需要与用户交互,只要在后台默默的工作,它就要使用Service
组件;不过只有很少的应用只会单独使用Service
组件。
将Service
按照创建的方式进行分类,有两种:启动Service-start Service
,绑定Service-bind Service
。前者使用startService()
运行,后者使用bindService()
运行。
如果站在Service与触发Service运行的那个组件的角度,根据它们的关系进行分类,有两种:本地Service,远程Service。
第2节 Start Service和Bind Service
我们先从从触发Service
运行的角度来认识Service
,有了整体的认识之后,我们再来看看远程Service和本地Service。
2.1 Start Service
其他组件通过调用startService()
函数将Service
运行起来,再通过调用stopService()
函数让其停止运行。
这种形式的Service
最为简单,它和它的调用者之间没有什么联系,调用者只是负责启动它和停止它。除此之外,两者没有数据交换、没有其他的功能调用,就像是合租房里合租的两个人,虽然住在一起(为同一个目标工作),但是基本上互不影响。
设计这样的一个Service
需要,
-
继承Android SDK提供的
Service
类,重写onBind()
函数,让他返回空值;public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { //不需要调用者和Service有功能调用,返回空值 return null; } ...... }
-
在
AndroidManifest.xml
中,声明新创建的Service
,<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> ...... <application ...... android:theme="@style/AppTheme"> ...... <!--声明新创建的Service--> <service android:name=".MyService" android:enabled="true" android:exported="true"></service> </application> </manifest>
使用这种Service
也很简单。假设Activity A中有个按钮start,点击之后就调用startService
;还有个按钮B-stop,点击之后就调用stopService
。
public void onClick(View v)
{
switch (v.getId())
{
case R.id.start:
{
//启动Service
Intent i = new Intent(this, MyService.class);
startService(i);
}
break;
case R.id.stop:
{
//停止Service
Intent i = new Intent(this, MyService.class);
stopService(i);
}
break;
}
}
这里运行Service的时候,是通过Intent
明确指定被运行的Service
。这种明确指定启动哪个Service
的方式叫做Service
的显示调用。与之对应的还有隐式调用。我们稍后来详细介绍。
2.2 Bind Service
其他组件通过调用bindService()
绑定Service
,让它运行起来;再通过调用unbindService()
解除绑定。
这种形式的Service
与调用者之间通常有功能调用或者数据交换,调用者会向Service
发出请求让Service
进行特定的操作,并返回结果。
设计这样的一个Service
需要,
-
继承Android SDK提供的
Service
类,public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { //暂时返回空值,写下来将进行改造 return null; } ...... }
-
实现一个自定义的
Binder
,让它这个继承Binder
类。Binder
可以将Service
与调用者联系起来,在Binder
中提供的方法,就是Service
对外提供的方法。组件和
Service
之间的调用是通过Binder
来进行的。我们可以把Binder
看作是一个连接其他组件和Service
的桥梁,它的实现原理是什么,我们暂时不用去关心,只要知道这样用就可以了。public class MyService extends Service { ...... //创建一个自定义的Binder public class MyServiceIBinder extends Binder { //提供给其他组件调用的方法 public void function1(int param) { //调用Service中真正实现功能的方法 innerFunction1(param); } } //真正实现功能的方法 private void innerFunction1(int param) { } //创建Binder实例 private final IBinder mBinder = new MyServiceIBinder(); @Override public IBinder onBind(Intent intent) { //当组件bindService()之后,将这个Binder返回给组件使用 return mBinder; } ...... }
-
在
AndroidManifest.xml
中,声明新创建的Service
,<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> ...... <application ...... android:theme="@style/AppTheme"> ...... <!--声明新创建的Service--> <service android:name=".MyService" android:enabled="true" android:exported="true"></service> </application> </manifest>
其他组件使用这个Service
的时候,
-
创建一个
ServiceConnection
,当绑定Service
之后在onServiceConnected()
中会得到Service
返回的Binder
;如果Service遇到异常情况退出时,会通过onServiceDisconnected
通知绑定它的组件。private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //这里的service参数,就是Service当中onBind()返回的Binder //获取访问Service的桥梁-MyServiceIBinder MyService.MyServiceIBinder bridge = (MyService.MyServiceIBinder) service; //通过桥梁就可以调用到Service提供到函数了 bridge.function1(0); } @Override public void onServiceDisconnected(ComponentName name) { //当Service遇到异常情况退出时,会通过这里通知绑定过它的组件 } };
获得了
MyService.MyServiceIBinder
之后,我们就可以向调用普通函数那样,调用到Service
对外提供的接口函数了。需要注意的是,如果用户主动解除绑定,
onServiceDisconnected()
是不会被触发的。 -
假设Activity A中有个按钮,点击之后就调用
bindService
;还有个按钮B,点击之后就调用unbindService
。public void onClick(View v) { switch (v.getId()) { case R.id.start: { Intent i = new Intent(this, MyService.class); bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE); } break; case R.id.stop: { unbindService(mServiceConnection); } break; } }
这里同样采用的是对
Service
的显示调用。
2.3 混合模式
Service
并不是只能给一个组件使用,它可以同时服务与多个组件。
所以一个Service
既可以是Start Service
,也可以是Bind Service
。只要把两者需要实现的地方都实现了就行。组件A可以通过startService()
运行一个Service
,组件B可以通过bindService()
再次运行同一个Service
。
2.3 显式调用和隐式调用
和Activity
一样,Service
有两种被调用的方式,显式调用和隐式调用。
2.3.1 显式调用
通过Intent
明确的指定要运行哪个Service
,这就是显式调用。
就好像给指定的个人发货,写下接收方具体的名字和地址。
设计显式调用,
//明确的指定了要运行的Service的类名、包名
Intent i = new Intent(this, MyService.class);
bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE);
通常,应用中的组件启动自己应用中的Service
,可以采用这样的方式,
Intent i = new Intent(this, MyService.class)
startService(i);
//或者
Intent i = new Intent(this, MyService.class)
bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE);
2.3.2 隐式调用
如果是应用A的组件要使用应用B的Service
,通常会使用到隐式调用,不明确的告知要启动的Service
是什么,而是通过Intent
的Action Name
让操作系统自己匹配最合适的响应者。
就好像给某个机构发货,只需要发送给某个机构,但不需要知道这个机构中具体是哪个人。
设计隐式调用,
-
AndroidManifest.xml
文件中为这个Service
指定一个过滤器,为过滤器指定一个Action name
,...... <application ...... android:theme="@style/AppTheme"> ...... <!--声明新创建的Service--> <service android:name=".MyService" android:enabled="true" android:exported="true"> <!--指定一个过滤器,为过滤器指定一个Action name--> <intent-filter> <action android:name="custom.service.remote" /> </intent-filter> </service> </application>
-
应用A的组件,要使用这个
Service
的时候,就可以,Intent i = new Intent("custom.service.remote"); i.setPackage("xxx.xxx.xxx");//Android5.0版本的以上的系统上要添加这一项,用来指定Service所在的包名 startService(i); 或者 Intent i = new Intent("custom.service.remote"); i.setPackage("xxx.xxx.xxx");//Android5.0版本的以上的系统上要添加这一项,用来指定Service所在的包名 bindService(i, mServiceConnection2, Context.BIND_AUTO_CREATE);
注意,对于Android5.0版本的以上的系统上要设置Intent发送目标的包名。因为从Android5.0开始,不允许隐式启动Service了。
- 1楼u0130433416天前 16:11
- 学习了,谢谢分享,多多加油!
- Re: anddlecn6天前 18:02
- 回复u013043341谢谢支持!