android Service完全解析

老规矩,先看官方文档是怎么说的。

A Service is an application component that can perform long-running operations in
 the background and does not provide a user interface. Another application 
 component can start a service and it will continue to run in the background even 
 if the user switches to another application. Additionally, a component can bind
  to a service to interact with it and even perform interprocess communication 
  (IPC). For example, a service might handle network transactions, play music, 
  perform file I/O, or interact with a content provider, all from the background.

以我的理解呢,大概就是说:

service是一个没有用户界面并且运行在后台以执行长时间耗时操作的app application组件。其它的application 组件能够启动service,而且service将一直执行下去,即使用户从当前service所属的application切换到了其它的application。另外,一个组件可以绑定到一个服务来和它交互,甚至是进程间通信(IPC机制)。for example,一个服务可能会处理网络操作,播放音乐,处理文件的IO操作,或者与content provider交互,所有的操作都是在后台完成的。

A service can essentially take two forms:

1.started

A service is "started" when an application component (such as an activity) starts
it by calling startService(). Once started, a service can run in the background 
indefinitely, even if the component that started it is destroyed. Usually, a 
started service performs a single operation and does not return a result to the
 caller. For example, it might download or upload a file over the network. When
  the operation is done, the service should stop itself.

2.Bound

A service is "bound" when an application component binds to it by calling 
bindService(). A bound service offers a client-server interface that allows 
components to interact with the service, send requests, get results, and even do
 so across processes with interprocess communication (IPC). A bound service runs 
 only as long as another application component is bound to it. Multiple 
 components can bind to the service at once, but when all of them unbind, the 
 service is destroyed.

1.started
当一个application 组件通过调用start Service()启动service之后service处于“started”形式。一旦service启动,它将在无限的后台运行,即使触发service的组件已经被销毁。通常,一个started的形式的service执行单一操作,并且不返回结果给启动它的组件。for example,它可能从网络下载或者上传文件。当操作结束后,service应该结束掉它自己。
2.Bound
当一个application组件通过调用bindService()使一个service处于“bound”形式。一个bound的service提供了一个C/S接口以完成application 组件和这个service的交互,send requests,getresults,甚至通过跨进成调度来通信。一个bound service只有在组件绑定它之后才可以运行。多个组件可以一次性绑定一个service,但是,当它们都取消绑定后,service将被销毁。

Although this documentation generally discusses these two types of services 
separately, your service can work both ways—it can be started (to run 
indefinitely) and also allow binding. It's simply a matter of whether you 
implement a couple callback methods: onStartCommand() to allow components to 
start it and onBind() to allow binding.

Regardless of whether your application is started, bound, or both, any 
application component can use the service (even from a separate application),
 in the same way that any component can use an activity—by starting it with an
  Intent. However, you can declare the service as private, in the manifest 
  file, and block access from other applications. This is discussed more in the 
  section about Declaring the service in the manifest.

这两段比价简单,只需要注意一下在manifest中声明service为你的application私有就好了。

Caution: A service runs in the main thread of its hosting process—the service 
does not create its own thread and does not run in a separate process (unless 
you specify otherwise). This means that, if your service is going to do any CPU 
intensive work or blocking operations (such as MP3 playback or networking), you
 should create a new thread within the service to do that work. By using a 
 separate thread, you will reduce the risk of Application Not Responding (ANR)
  errors and the application's main thread can remain dedicated to user 
  interaction with your activities.

慎重处理:一个service运行在当前进程的主线程中,service不能为自己创建线程也不能在另外的进程运行。这就意味着,如果你的service将要执行一些CPU密集型操作,或者线程阻塞操作(such as MP3 playback or networking),你应该新建一个包含该service的线程来执行此类操作。通过使用另一个线程,你的application将减少了引发ANR错误的可能性,并且你的主线程将保留这来进行与用户的交互活动。


延伸阅读 :Should you use a service or a thread?

A service is simply a component that can run in the background even when the 
user is not interacting with your application. Thus, you should create a 
service only if that is what you need.

If you need to perform work outside your main thread, but only while the user 
is interacting with your application, then you should probably instead create a 
new thread and not a service. For example, if you want to play some music, but 
only while your activity is running, you might create a thread in onCreate(), 
start running it in onStart(), then stop it in onStop(). Also consider using 
AsyncTask or HandlerThread, instead of the traditional Thread class. See the
 Processes and Threading document for more information about threads.

Remember that if you do use a service, it still runs in your application's main
 thread by default, so you should still create a new thread within the service 
 if it performs intensive or blocking operations.

有了前面的铺垫,相比此处很容易裂理解吧,贴出来只是为了大家使用thread和service更容易的思考和抉择。


好,现在来看一下Service的生命周期:

Alt text

package me.androiddemo.canglangwenyue.androiddemo;

 android.app.Service;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.IBinder;

import java.io.FileDescriptor;
import java.io.PrintWriter;

/**
 * Created by canglangwenyue on 12/7/14.
 */
public class MyService extends Service {
public MyService() {
    super();
}

@Override
public void onCreate() {
    super.onCreate();
     Notification notification = new Notification(R.drawable.ic_launcher, getText(R.string.app_name),
            System.currentTimeMillis());
    Intent notificationIntent = new Intent(this, MyService.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    notification.setLatestEventInfo(this, getText(R.string.hello_world),
            getText(R.string.hello_world), pendingIntent);
    startForeground(1, notification);
}

@Override
public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
    super.onDestroy();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
}

@Override
public void onLowMemory() {
    super.onLowMemory();
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
}

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

@Override
public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
}

@Override
public void onRebind(Intent intent) {
    super.onRebind(intent);
}

@Override
public void onTaskRemoved(Intent rootIntent) {
    super.onTaskRemoved(rootIntent);
}

@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
    super.dump(fd, writer, args);
}
    }

记得在manifest文件里注册service,

Alt text

可以在onCreate()方法中启动一个notification,是你的service显示在通知栏,当然这里只是简单的显示,具体可可以做更多的工作。然后在需要启动service的activity里面用

Intent intent = new Intent(this,MyService.class);

startService(intent);

来开始一个 service。


好了,既然Service已经写到这种程度了,那么我们就再接再厉来看看IntentService吧,并比较一下如何在service与IntentService之间抉择,让大家更好地理解。

Service

This is the base class for all services. When you extend this class, it's 
important that you create a new thread in which to do all the service's work, 
because the service uses your application's main thread, by default, which 
could slow the performance of any activity your application is running.
IntentService

This is a subclass of Service that uses a worker thread to handle all start 
requests, one at a time. This is the best option if you don't require that your 
service handle multiple requests simultaneously. All you need to do is 
implement onHandleIntent(), which receives the intent for each start request so 
you can do the background work.

Service

这是所有services的基类。当你extendsService之后,你是在你的application的main thread中创建了一个用于执行所有service's work的新线程,默认的,这种行为会降低你的activity正在执行的任何activity的性能。

IntentService

IntentService是Service类的子类,它用一个工作线程来处理所有的requests,而且一次只能执行一个。如果你不要求你的Service同时执行多个请求,那么IntentService便是最好的选择。你所需要做的只是实现onHandleIntent()onHandleIntent()用来接收每个请求并在后台工作。使用Service使必须另开线程,而使用IntentService则不需要,因为framework默认实现了一个worker thread。IntentService自己维护了一个队列,他会一个接一个的处理request。

好了,那么来看一下,官网上IntentService的实现:

public class HelloIntentService extends IntentService {

  /** 
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with 
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
  // Normally we would do some work here, like download a file.
  // For our sample, we just sleep for 5 seconds.
  long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}

好了,现在应该是很简单了,有木有。注意IntentService一般和LocalBroadcastManager组合使用,从而使得IntentService将任务执行的任务状态与结果返回给任务的发送方。

官方文档地址:

API Guides

Reference

嗯嗯,就写到这里了。