您的位置:首页 > 移动开发 > Android开发

Android四大组件--Service详解

2017-10-22 10:43 561 查看
Service 作为 Android 四大组件之一,可以说是一个合格的 Android 应用的基石。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,依然让 Service 在后台保持运行状态。

1、Service介绍

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

服务基本上分为两种形式:

启动

当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。 操作完成后,服务会自行停止运行。

绑定

当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

对于 Service 的介绍,官方有详细的介绍

2、基本用法

关于 Service 最基本的用法当然是在程序中启动一个 Service 啦,我们就来介绍下这个流程。

首先写一个继承 Service 的类:

public class MyService extends Service {

@Override
public void onCreate() {
super.onCreate();
Log.d("TAG", "onCreate()");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

Log.d("TAG", "onStartCommand");

return super.onStartCommand(intent, flags, startId);
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}


Service 也有 onCreate(),具体的在下面介绍,Service 第一次被创建就会调用 onCreate()。

Service 的启动与 Activity 的方式相似,也是使用 Intent:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
}


每一个 Service 我们若想使用都必须在 AndroidManifest.xml 中注册,在 application 标签下:

<service android:name=".MyService"/>


这样 MyService 就可以启动了。

要想停止 Service,调用一下 stopService():

stopService(intent);


在 AndroidManifest.xml 中,service 元素的几个属性:

android:name:服务类名,唯一必需的属性。

android:label:服务的名字,如果此项不设置,那么默认显示的服务名则为类名。

android:icon:服务的图标。

android:permission:申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务。

android:process:表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字。

android:enabled:表示是否能被系统实例化,为true表示可以,为false表示不可以,默认为true。

android:exported:表示该服务是否能够被其他应用程序所控制或连接,其默认值是由 Service 中有无 intent-filter 决定的,如果有 intent-filter,默认值为 true,否则为 false。为 false 的情况下,即使有 intent-filter 匹配,也无法打开。

3、启动和绑定

上面说过 Service 分为两种方式,启动和绑定,这两种都可以实现服务的启动,这也使得 Service 的启动到销毁出现两种路径:



先来介绍下最重要的几种回调方法:

onCreate()

首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。如果服务已在运行,则不会调用此方法。

onStartCommand()

当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果您实现此方法,则在服务工作完成后,需要由您通过调用 stopSelf() 或 stopService() 来停止服务,服务使用 stopSelf() 自行停止运行,其他组件通过调用 stopService() 停止。(如果您只想提供绑定,则无需实现此方法。)

onBind()

当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,您必须通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信。请务必实现此方法,但如果您并不希望允许绑定,则应返回 null。

onDestroy()

当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。

onStartCommand() 的返回值这里特别说明,它有三种可选值,如下:

START_STICKY

当 Service 因内存不足而被系统 kill 后,一段时间后内存再次空闲时,系统将会尝试重新创建此 Service,一旦创建成功后将回调 onStartCommand 方法,但其中的 Intent 将是 null,除非有挂起的 Intent,如 pendingintent,这个状态下比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。

START_NOT_STICKY

当 Service 因内存不足而被系统 kill 后,即使系统内存再次空闲时,系统也不会尝试重新创建此 Service。除非程序中再次调用 startService() 启动此 Service,这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。

START_REDELIVER_INTENT

当 Service 因内存不足而被系统 kill 后,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand(),任何挂起 Intent 均依次传递。与 START_STICKY 不同的是,其中的传递的 Intent 将是非空,是最后一次调用 startService() 中的 intent。这个值适用于主动执行应该立即恢复的作业(例如下载文件)的服务。

4、绑定服务

绑定服务是客户端-服务器接口中的服务器。绑定服务可让组件(例如 Activity)绑定到服务、发送请求、接收响应,甚至执行进程间通信 (IPC)。 绑定服务通常只在为其他应用组件服务时处于活动状态,不会无限期在后台运行。

前面介绍了用 startService() 来启动 Service,现在来介绍下用 bindService() 该怎么做。

因为要绑定服务,就得为组件提供一个接口 Binder,所以我们首先要在 Service 中写一个 Binder 类,然后在 onBind() 中返回 Binder 对象:

public class MyService extends Service {

private MyBinder mBinder = new MyBinder();

@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}

class MyBinder extends Binder {
public void download() {
Log.d("TAG", "download");
}
}
}


我们在 Binder 类里写自己的逻辑,必须实现 onBind() 回调方法以返回 IBinder,用于定义与服务通信的接口。

public class MainActivity extends AppCompatActivity {

private MyService.MyBinder mBinder;

private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (MyService.MyBinder) service;
mBinder.download();
}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, connection, BIND_AUTO_CREATE);
}
}


应用组件(客户端)可通过调用 bindService() 绑定到服务。Android 系统随后调用服务的 onBind() 方法,返回用于与服务交互的 IBinder。

绑定是异步的。bindService() 会立即返回,“不会”使 IBinder 返回客户端。要接收 IBinder,客户端必须创建一个 ServiceConnection 实例,并将其传递给 bindService()。

ServiceConnection 包括两个回调方法:

onServiceConnected()

系统会调用该方法以传递服务的 onBind() 方法返回的 IBinder。

onServiceDisconnected()

Android 系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法。当客户端取消绑定时,系统“不会”调用该方法。

当系统调用我们的 onServiceConnected() 回调方法时,就可以使用接口定义的方法开始调用服务。

bindService() 方法第三个参数是一个指示绑定选项的标志。它通常应该是 BIND_AUTO_CREATE,以便创建尚未激活的服务,在Activity和Service建立关联后自动创建Service,这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。其他可能的值为 BIND_DEBUG_UNBIND 和 BIND_NOT_FOREGROUND,或 0(表示无)

要断开与服务的连接,使用 unbindService() 方法:

unbindService(connection);


如果既使用了 startService() 又使用了 bindService(),单独使用 stopService() 或者 unbindService() 都不能销毁 Service,不会触发 onDestroy()。因为一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁,所以这两个方法必须都被调用,顺序不定。

如果你只是想要启动一个后台服务长期进行某项任务,那么使用 startService() 便可以了。如果你还想要与正在运行的 Service 取得联系,那么有两种方法:一种是使用 broadcast,另一种是使用 bindService()。前者的缺点是如果交流较为频繁,容易造成性能上的问题,而后者则没有这些问题。

注意 Service 也是运行在主线程里的,我们要做耗时操作就要在 Service 中创建子线程。

还有个远程 Service,这个可以用到 AIDL 实现,可以看看我的博客Android–AIDL基础介绍

结束语:本文仅用来学习记录,参考查阅。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: