您的位置:首页 > 其它

四大组件之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了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: