四大组件之Service(一)-双子座的Service-Start Service与Bind Service
2016-06-12 13:59
375 查看
第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了。
相关文章推荐
- Struts2学习笔记(1)
- 【二分图匹配】完美的牛栏
- VS内存断点
- Django中文显示
- MVP模式在Android项目中的使用
- PHP会员找回密码功能实现实例介绍
- Batch Normalization 导读
- enum枚举详解
- 如何让Ubuntu系统支持WebP图片格式
- Python 元组详解
- POI操作WORD文档,生成的新文档为空白文档 -- 待解决
- django传递数据给JS
- Solr/SolrCloud SearchHandler详解
- html 时间单位
- [BZOJ4198][Noi2015]荷马史诗
- 我所理解的设计模式
- 卸载loadrunner12.5,安装11.0遇到问题
- SICP Table
- CSS 实现导航条
- 高德地图定位相关API