Service小结

一、简介

Service 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。
注意:服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。

二、AndroidManifest配置

使用Service必须在AndroidManifest中注册,如下:

...




可以为service配置一些特定属性。
android:exported=["true" | "false"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >

android:name:属性是唯一必需的属性,用于指定服务的类名。
android:enabled:是否可被系统实例化,默认true.
android:exported : 设为false则其它应用(user ID不同)无法启动此服务。默认true。
android:permission:指定启动服务及其运行所在进程所需的权限。
android:process:指定服务运行进程,默认当前应用进程。
注意:Android5.0以后禁止了隐式声明Intent来启动Service。可以通过setPackage()解决或者把一个隐式Intent转换成显式Intent。

三、Service的生命周期

service_lifecycle.png

public class ExampleService extends Service {
int mStartMode; // 声明服务如果被系统回收之后的行为
IBinder mBinder; // 返回的用于和Service交互的Binder
boolean mAllowRebind; // 声明onRebind是否被使用
@Override
public void onCreate() {
// 服务正被创建
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 由于调用了startService(),服务正在启动
// 返回值表明了服务如果被系统回收之后的行为
// 返回值START_NOT_STICKY
// 返回值START_STICKY
// 返回值START_REDELIVER_INTENT
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// 由于调用了bindService(),服务正在绑定
// 返回Binder
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// 服务的所有绑定都调用了unbindService()
// 返回值决定是否允许调用onRebind
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
//调用了onUnbind并返回true,再次调用bindService()
}
@Override
public void onDestroy() {
//服务被销毁
}
}

对于长时间运行的服务,系统会随着时间的推移降低服务在后台任务列表中的位置,而服务也将随之变得非常容易被终止。当内存过低且必须回收系统资源以供具有用户焦点的 Activity 使用时,Android 系统就会强制停止服务。
如果将服务绑定到具有用户焦点的 Activity,则它不太可能会终止;
如果将服务声明为前台服务,则它几乎永远不会终止。
如果服务是启动服务,则您必须将其设计为能够妥善处理系统对它的重启。因为如果系统终止服务,那么一旦资源变得再次可用,系统便会重启服务。

四、IntentService

IntentService是Service的子类,创建了默认线程,使用者只需实现onHandleIntent()即可,IntentService具体执行操作如下:
1.创建默认的工作线程,用于在应用的主线程外执行传递给onStartCommand()的所有 Intent。
2.创建工作队列,用于将一个 Intent 逐一传递给onHandleIntent()实现,这样您就永远不必担心多线程问题。
3.在处理完所有启动请求后停止服务,因此您永远不必调用stopSelf()。
4.提供onBind()的默认实现(返回 null)。
5.提供onStartCommand()的默认实现,可将Intent 依次发送到工作队列和onHandleIntent()实现。
代码实现:
public class TestIntentService extends IntentService {
// 必须实现的构造函数
//且需要调用父类的构造函数,传入的参数就是创建的工作线程的名字
public TestIntentService() {
super("word_thread_name");
}
//唯一要实现的方法,方法返回则服务停止
@Override
protected void onHandleIntent(Intent intent) {
}

五、startService

5.1简介

启动服务:startService(Intent intent)
停止服务:stopService(Intent intent);
如果组件通过调用startService()启动服务(这会导致对onStartCommand()
的调用),则服务将一直运行,直到服务使用stopSelf()自行停止运行,或由其他组件Intent会重新传递给Service。

5.2 创建一个Service

public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread("name");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
}
}

每次startService都会回调onStartCommand方法。在这个方法中,我们拥有在运行Service时传递进来的Intent,这样就可以与Service交换一些信息。这个方法需要返回一个整型值。这个整型代表系统应该怎么样处理这个Service:
START_STICKY:使用这个返回值,如果系统杀死我们的Service将会重新创建。但是,发送给Service的Intent不会再投递。这样Service是一直运行的。
START_NOT_STICKY:如果系统杀死了Service,不会重新创建,除非客户端显式地调用了onStart命令。
START_REDELIVER_INTENT:功能与START_STICKY类似。另外,在这种情况下

5.3 前台运行服务

前台服务被认为是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。
通过调用startForeground()设置服务为前台服务,代码如下:
Intent notificationIntent = new Intent(this, ServiceActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_launcher) .setWhen(System.currentTimeMillis())
.setContentText("content")
.setContentTitle("title")
.setContentIntent(pendingIntent)
.build();
startForeground(1111, notification);

注意:前台服务必须为状态栏提供通知,状态栏位于“正在进行”标题下方,这意味着除非服务停止或从前台删除,否则不能清除通知。

5.4 向用户发送通知

服务可以发送Toast通知和状态栏通知两种。

六、bindService

6.1简介

绑定服务:bindService(Intent intent,ServiceConnection conn,int flags)
解除绑定:unbindService(ServiceConnection conn)
如果组件是通过调用bindService()来创建服务,则服务只会在该组件与其绑定时运行。一旦该服务与所有客户端之间的绑定全部取消,系统便会销毁它。

6.2绑定Service

要想绑定服务,必须:
1.实现 ServiceConnection。
重写两个回调方法:
onServiceConnected()
绑定时调用,传递onBind()的返回值。
onServiceDisconnected()
当服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法。注意:取消绑定时并不会调用。
2.调用 bindService()
传递ServiceConnection对象
3.调用 unbindService()取消绑定。
注意:当Activity被销毁时,会取消与服务的绑定。但您应该始终在完成与服务的交互时或您的 Activity 暂停时取消绑定,以便服务能够在未被占用时关闭。

6.3扩展Binder

如果服务是自有应用专用,并且在相同的进程中运行,则应通过扩展 Binder 类并从onBind() 返回它的一个实例来创建接口。
以下是具体的设置方法:
1 在您的服务中,创建一个可满足下列任一要求的Binder实例:
包含可调用的公共方法
返回当前Service实例,Service中包含可调用的公共方法
或返回由服务承载的其他类的实例,其中包含可调用的公共方法
2.从onBind()回调方法返回此Binder实例。
3.从onServiceConnected()回调方法中接收Binder

注意:之所以要求服务和客户端必须在同一应用内,是为了便于客户端转换返回的对象和正确调用其 API。服务和客户端还必须在同一进程内,因为此方法不能任何跨进程执行。如果服务只是您的自有应用的后台工作线程,则优先采用这种方法。 不以这种方式创建接口的唯一原因是,您的服务被其他应用或不同的进程占用。

6.4使用Messenger

如需让接口跨不同的进程工作,则可使用 Messenger 为服务创建接口。服务可以这种方式定义对应于不同类型 Message 对象的 Handler。此 Handler 是 Messenger 的基础,后者随后可与客户端分享一个IBinder,从而让客户端能利用 Message 对象向服务发送命令。此外,客户端还可定义自有Messenger,以便服务回传消息。
以下是具体步骤:
1.服务实现一个 Handler,由其接收来自客户端的每个调用的回调
2.Handler 用于创建 Messenger 对象(对 Handler 的引用)
3.Messenger 创建一个 IBinder,服务通过 onBind() 使其返回客户端
4.客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务
5.服务在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message
public class MessageService extends Service {
private Messenger message = new Messenger(new MesHandler());
@Override
public IBinder onBind(Intent intent) {
return message.getBinder();
}
class MesHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}

这是执行进程间通信 (IPC) 的最简单方法,因为 Messenger 会在单一线程中创建包含所有请求的队列,这样您就不必对服务进行线程安全设计。

6.5使用AIDL

如需直接使用 AIDL,您必须创建一个定义编程接口的 .aidl 文件。Android SDK 工具利用该文件生成一个实现接口并处理 IPC 的抽象类,您随后可在服务内对其进行扩展。
之前采用 Messenger 的方法实际上是以 AIDL 作为其底层结构。Messenger 会在单一线程中创建包含所有客户端请求的队列,以便服务一次接收一个请求。不过,如果您想让服务同时处理多个请求,则可直接使用 AIDL。 在此情况下,您的服务必须具备多线程处理能力,并采用线程安全式设计。

6.6注意事项

1.应该始终捕获 DeadObjectException 异常,它是在连接中断时引发的,也是远程方法引发的唯一异常
2.对象是跨进程计数的引用
3.通常应配对绑定和取消绑定。
例如:在 onStart() 绑定, onStop() 取消绑定。或者在 onCreate() 绑定,onDestroy() 取消绑定。
4.通常情况下,切勿在 Activity 的 onResume() 和 onPause() 期间绑定和取消绑定,因为每一次生命周期转换都会发生这些回调,您应该使发生在这些转换期间的处理保持在最低水平。
5.此外,如果您的应用内的多个 Activity 绑定到同一服务,并且其中两个 Activity 之间发生了转换,则如果当前 Activity 在下一次绑定(恢复期间)之前取消绑定(暂停期间),系统可能会销毁服务并重建服务。 (Activity文档中介绍了这种有关 Activity 如何协调其生命周期的 Activity 转换。)

你可能感兴趣的:(Service小结)