Service 特点

  • 适用于耗时操作,并且不需要与用户交互的功能。
  • 其他应用程序组件能够启动服务并且即使用户切换到另一个应用,服务还可以在后台运行。
  • 组件能够绑定到服务并与之交互,甚至执行进程间通信。
  • Service 比处于非活动状态的Activity更高的优先级,因此当系统请求资源时,它们被终止的可能性很小。如果运行时过早得终止了一个已经启动的Service,只要有足够的资源可用,则运行时就会重新启动它。
  • 一个Service的优先级可以提升到和前台Activity的优先级一样高。
  • 开发人员可以将服务设为私有从而阻止其他应用程序访问。
  • 虽然Service在运行的时候没有专门的GUI,但是它们和Acitivity以及BroadCast Receiver一样还是运行在应用程序进程的主线程中,因此必须通过Thread和AsyncTask类把耗时的进程移到后台进程中。通过使用独立的线程,开发人员能减少应用不相应错误的风险,并且应用程序主线程仍然用于用户与Activity交互。

Service 的类型

  • Started Service:当应用程序组件通过调用startService()方法启动服务时候,服务处于started状态。一旦启动,服务能够在后台无期限运行,即使启动它的组件已经被销毁。通常,Started Service执行单个操作并且不会向调用者返回结果。如果操作完成,服务需要停止自身.
  • Bound Service :当应用程序通过bindService()方法绑定到服务的时候,服务处于bound状态,绑定服务提供客户端-服务器接口,以允许组件与服务交互,发送请求,获得结果,甚至使用进程间通信跨进程完成这些操作。仅当其他应用程序组件与之绑定的时候,绑定服务才能运行。多个组件可以绑定到一个服务上。只有在他们都解除绑定的时候服务被销毁。
    服务也可以同时属于上述两种类型既可以启动,无限期运行,可能绑定。这取决于是否实现一些回调方法:onStartCommand()方法允许组件启动,onBind方法允许组件绑定服务。

Service的生命周期

  1. OnStarted方式启动
  2. OnBound方式启动
  • onStartCommand()
    当其他组件,如Activity调用startService()方法请求服务启动的时候,系统调用该方法,一旦该方法执行,服务就启动,并在后台无限期运行。如果开发人员实现该方法,则需要在任务完成时候调用stopSelf()或者stopService()方法停止服务。

  • onBind()
    当其他组件调用bindService方法想与服务绑定的时候,系统调用该方法,在该方法的实现中,开发人员必须通过返回IBinder提供客户端用来与服务通信的接口。该方法必须实现,但是如果不想允许绑定,则应该返回null;

  • onCreate()
    当服务第一创建时,系统调用该方法执行一次性建立(在系统调用onStartCommand()或onBind()方法前)如果服务已经运行,该方法不被调用,从而保证在Android系统中一个Service只有一个实例。

  • onDestroy()
    当服务不再使用并即将销毁时,系统调用该方法。服务应该实现该方法来清除诸如线程,注册监听器,接收者等资源。这是服务受到的最后调用。

Service的声明

开发人员必须在应用程序配置文件中声明全部的Service,方法是在标签中添加子标签。

创建Service

一般方式创建

应用程序组件例如Activity能通过StartService()方法或者传递Intent对象来启动服务,在Intent对象中指定了服务并且包含服务所需要的全部数据,服务使用onStartCommand方法接收Intent。
实验及结果分析:代码见TestService

  • 按下Start Service 启动服务,这是输出结果如下:
  • 按下后退键和Home键,不会输出onDestroy,说明即使按下这两个键,服务仍然在后台运行,可以在Setting->Application 中查看到。
  • 再次点击App图标进入输出如下结果:说明一个Service在Android 系统中只存在一个实例,在已经存在的情况下不会再次调用onCreate创建新的Service。
  • 按下StopService,结果如下:
继承IntentService类

IntentService:这是Service的子类,它每次使用一个工作线程来处理全部启动请求,在不必同时处理多个请求时候,这是最佳选择。开发人员需要实现onHandleIntent方法,它接收每次启动请求的Intent以便完成后台的任务

  • 创建区别于主线程的默认工作线程来执行发送到onStartCommand方法的全部Intent
  • 创建工作队列每次传递一个Intent到onHandleIntent方法实现,这样就不必担心多线程。
  • 所有启动请求处理完毕后停止服务,这样就不要调用stopself方法。
    实现方法:
  • 提供OnBind方法实现,其返回值是null;
  • 提供onStartCommand方法的默认实现,它先发送Intent到默认队列,然后到onHandleIntent方法实现。
    我们要做的工作就是实现onHandleIntent方法,同时由于IntentService并没有提供空参数的构造方法因此必须提供一个构造方法。
    例子:
public class HelloIntentService extends IntentService {
public HelloIntentService() {
super("Hello Service");
}
protected void onHandleIntent(Intent intent) {

long endTime = System.currentTimeMillis()+5*1000;
while(System.currentTimeMillis()<endTime){
synchronized (this) {
try {
wait(endTime-System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
System.out.println("onHandleIntent");
}
}
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Server Start: "+"flags:"+flags+"start ID:"+startId, Toast.LENGTH_LONG).show();
return super.onStartCommand(intent, flags, startId);
}
public IBinder onBind(Intent intent) {
return null;
}
}
private Button btn = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent= new Intent(MainActivity.this,HelloIntentService.class);
startService(intent);
}
});
}

实验结果分析:

按下Start IntentService 后输出如下结果:
从结果可以看出,IntentService 会在onHandleIntent方法中处理业务逻辑部分,同时在处理完成后会自动销毁服务,而不需调用stopself/stopService方法。(调用StopService方法不会调用onDestroy方法销毁服务)

继承Service类

使用IntentService类可以简化启动服务的实现,然而,如果需要让服务处理多线程,取代使用工作队列启动请求,也就是说为每次请求创建一个新线程并且立即运行它们,避免等待前一个请求的结束,则可以继承Service类来处理各个Intent
Service:是所有服务的基类,当继承该类的时候,创建新线程来执行服务的全部工作是非常重要的,因为默认服务默认是使用应用程序主线程,这可能会降低应用程序Activity的运行性能。
这种方法要自己使用stopself或者stopService方法结束服务,并且需要自己创建线程来处理服务的内部逻辑
使用这种方式的时候onStartCommand必须返回一个整数。用于表示系统停止服务后如何继续服务。

1. START_NOT_STICKY:如果系统在onStartCommand方法返回后停止服务,则系统不会重新创建服务,除非有PendingIntent要发送。在避免在不必要时运行服务和应用程序能简单地重启任何未完成工作的时候,这是最佳选择。
2. START_STICKY:如果系统在onStartCommand方法返回后停止服务,则系统会重新创建服务并调用onStartCommand方法。但是不重新发送最后的Intent,相反系统使用空Intent调用onStartCommand方法,除非有PeddingIntent来启动服务。此时,这些Intent会发送。这适合多媒体播放器,它们不执行命令但是无限期运行并等待工作。
3. START_REDELIVER_INTENT:如果系统在onStartCommand方法返回后停止服务,重新创建服务并使用发送给服务的最后Intent调用onStartCommand方法,全部PenddingIntent必须依次发送,这适合积极执行应该立即恢复工作的服务。如下载文件。

启动和停止服务

启动服务不能直接调用onStartCommand方法,而是使用Acitivity或者其他应用程序组件通过传递Intent对象到startService()方法启动服务。Android系统自动调用服务的onStartCommand方法并将Intent传递给它,如果服务还没有运行系统首先调用onCreate()方法,接着调用onStartCommand方法。
如果服务没有绑定,StartService方法发送的Intent是应用程序和服务之间唯一的通信方式,然而如果需要获得服务的放回结果,则可以通过启动该服务的客户端能为广播创建PeddingIntent并通过启动服务的Intent发送它,服务接下来能使用广播发送结果。

Started Service方式的服务,系统不会停止或者销毁它,它的生命周期必须自己管理。除非它必须回收系统内存并且在onStartCommand方法返回后服务继续运行,因此服务必须调用stopSelf方法停止自身或者其他组件调用stopService方法停止服务。
stopself(startid)方法可以确保停止服务的请求总是基于最近接收到的启动请求。

创建Bound Service

绑定服务是允许其他应用程序绑定并且与之交互的Service类实现类。为了提供绑定,开发人员必须实现onBind回调方法。该方法返回iBinder对象,它定义了客户端用来与服务交互的程序接口.
客户端能通过bindService方法绑定到服务,此时客户端必须提供ServiceConnection接口的实现类。它监视客户端与服务之间的联系,bindService立刻放回,但是当Android系统创建客户端与服务之间的连接时,它调用ServiceConnection 接口中的onServiceConnection方法来发送客户端用来发送与服务通信的IBinder对象。
多个客户端能够同时连接到服务,但是仅当第一个客户端绑定的时候,系统调用服务的onBind方法来获取Ibinder对象,系统接着发送同一个IBinder对象到其他的绑定的客户端但是不再调用onBind方法,当最后的客户端与服务解除绑定的时候,系统销毁服务。

绑定和解除绑定

应用程序能调用bindService方法绑定到服务,android系统接下来调用服务的onBind方法,它返回IBinder来与服务通信。绑定是异步的bindService方法立刻返回,为了接收IBinder。客户端必须创建ServiceConnection实例然后传递到bindService方法。
只有Activity,Service,Content Provider能够绑定到服务,BroadcastReceiver不能绑定到服务。
如果需要从客户端绑定服务需要完成如下工作:

  1. 实现ServiceConnection这需要重写onServiceConnected和onserviceDisconnected方法
  2. 调用bindService传递ServiceConnection实现。
  3. 当系统调用onServiceConnected方法的时候,就可以使用接口定义的方法。
  4. 调用unbindService解除绑定。

将Service移到前台

在确定哪个应用程序或者应用程序组件可以被终止的时候,Android给正在运行的Service赋予了第二高的优先级,仅仅次于处于激活状态,并且在前台与用户交互的活动Acitivity,在Service需要直接和用户进行交互的情况下,可以将Service的优先级提高到和前台Activity一样高,可以通过调用Service的startForeground方法来将一个服务移到前台,同样可以调用stopForeground来将一个服务移到后台。

int NOTIFICATION_ID = 1;
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 1, intent, 0);
Notification notification = new Notification(R.drawable.ic_launcher, "前台服务", System.currentTimeMillis());
notification.setLatestEventInfo(this, "前台服务", "这个是被移到前台的服务", pi);
notification.flags =notification.flags|Notification.FLAG_ONGOING_EVENT;
startForeground(NOTIFICATION_ID,notification);

提升服务存活可能性的方法

http://blog.csdn.net/mad1989/article/details/22492519

  • onStartCommand方法,返回START_STICKY
  • 提升service优先级
    <service  
    android:name="xxxxxxx"
    android:enabled="true" >
    <intent-filter android:priority="1000" >
    ...............
    </intent-filter>
    </service>
  • 使用startForeground()提升service进程优先级
  • onDestroy方法里重启service
  • 监听系统广播判断Service状态
  • 将应用升级为系统应用
  • Application加上Persistent属性
<application  
android:name="xxxxxxxxxxx"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:persistent="true"
android:theme="@style/AppTheme" >
</application>
Contents
  1. 1. Service 特点
  2. 2. Service 的类型
  3. 3. Service的生命周期
  4. 4. Service的声明
  5. 5. 创建Service
    1. 5.1. 一般方式创建
    2. 5.2. 继承IntentService类
    3. 5.3. 继承Service类
  6. 6. 启动和停止服务
  7. 7. 创建Bound Service
  8. 8. 绑定和解除绑定
  9. 9. 将Service移到前台
  10. 10. 提升服务存活可能性的方法