Services

阅读:http://developer.android.com/guide/components/services.html

Services是一个长时间操作而且不提供界面的组件。程序里其他的组件都能够启动它并且就算用户切换了其他的程序,Services也仍然运行着。

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.

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.

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.

Services有两种形式,一种是直接开始,一种是绑定程序组件。

直接开始模式中,就算启动它的程序组件被摧毁了,直接开始不会受影响仍然运行着。

绑定模式能够让程序组件与Services通过client-server 接口进行交流。一个绑定的services能够被多个程序组件绑定,并且只有绑定的时候才运行,当没组件绑定的时候,service被摧毁。

一个service也可以同时拥有这两者形式。


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在主线程中运行,它并没有新建一个线程也没有在单独的线程里运行。如果你需要大量CPU运算操作或者锁定操作那么你就应该在service中新建一个线程。


集成service需要实现几个重要的方法:

onStartCommand():一旦程序组件运行service,就是运行这个方法里的代码,并且是后台执行。

onBind():如果需要绑定,就要实现它。一旦有程序组件要绑定他,就会执行这个方法,在这个方法里,必须返回一个IBinder对象作为交流载体。

onCreate():一旦service被创建,就会执行该方法。

onDestroy():service被摧毁时运行的方法,注意,在这里要释放所有资源。

stopSelf() , stopService().:一个是自己停止,一个是被动停止。


The Android system will force-stop a service only when memory is low and it must recover system resources for the activity that has user focus. If the service is bound to an activity that has user focus, then it's less likely to be killed, and if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system. If the system kills your service, it restarts it as soon as resources become available again (though this also depends on the value you return from onStartCommand(), as discussed later). For more information about when the system might destroy a service, see the Processes and Threading document.

  当内存不足的时候,系统会结束一些service。

  如果这个service有组件绑定了,很少可能会被结束。

  如果service在前台被执行,那么它不会被结束。

  如果一个service运行很久了,那么系统会降低它的优先级,那么它极有可能会被结束。

  如果系统结束了你的service,之后再资源许可的情况下,它会恢复它,因此你要做好service的设计。


<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

像Activity一样,必须在manifest定义好service。

同样的,你可以定义好一个service的intent filters,使得他能够被其他程序调用。如果只想被自己调用,就不同定义这些了,或者直接设置android:exported属性为“false”。


An application component such as an activity can start the service by calling startService() and passing anIntent that specifies the service and includes any data for the service to use. The service receives this Intentin the onStartCommand() method.

For instance, suppose an activity needs to save some data to an online database. The activity can start a companion service and deliver it the data to save by passing an intent to startService(). The service receives the intent in onStartCommand(), connects to the Internet and performs the database transaction. When the transaction is done, the service stops itself and it is destroyed.

  组件可以通过intent来启动service,并且可以通过它来传递数据。

  例如要上传某段文本,那么只需要在intent加入数据,然后启动service,service的startService()就会获取到intent的内容然后连接互联网并上传,最后它会结束自己并且被摧毁。


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.

这两个类是供你选择的,第一个比较基础,因此需要自己多很多操作,例如新建线程等。而第二个类则包装好了,只需要是想onHandleIntent()方法即可。


The IntentService does the following:

  • Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.
  • Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.
  • Stops the service after all start requests have been handled, so you never have to call stopSelf().
  • Provides default implementation of onBind() that returns null.
  • Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation.

  IntentService做了一下几件事:

  1、为任务创建线程;

  2、创建了任务队列以此来应付多任务模式;

  3、当所有任务完成的时候自动Stopped,无需使用StopSelf;

  4、onBind()永远返回NULL;

  5、自动将onStartCommand()传来的intent排成队列以便串行处理


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并且必须写构造器,而且必须传入字串符以作为线程标识;


public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // 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) {
                  }
              }
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    
    // Get the HandlerThread's Looper and use it for our Handler 
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      
      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }
  
  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); 
  }
}

同样的功能在service类实现就困难多了。

首先创建一个handle类,之后绑定到新建的HandleThread子线程中(通过获得子线程的Lopper),然后通过对handle的实例控制使用sendmassage()。

虽然麻烦,但是由于可控性高,我们完全可以自己给每个任务新建一个线程,而不是一个线程串行运行。

onStartCommand必须返回一个整数,例如:return START_STICKY;


Intent intent = new Intent(this, HelloService.class);
startService(intent);

The startService() method returns immediately and the Android system calls the service's onStartCommand()method. If the service is not already running, the system first calls onCreate(), then calls onStartCommand().

上面是调用service的方法,如果service已经存在则直接调用onStartCommand(),不存在则先初始化(oncreate)。


Stopping a service

A started service must manage its own lifecycle. That is, the system does not stop or destroy the service unless it must recover system memory and the service continues to run after onStartCommand() returns. So, the service must stop itself by calling stopSelf() or another component can stop it by calling stopService().

Once requested to stop with stopSelf() or stopService(), the system destroys the service as soon as possible.

However, if your service handles multiple requests to onStartCommand() concurrently, then you shouldn't stop the service when you're done processing a start request, because you might have since received a new start request (stopping at the end of the first request would terminate the second one). To avoid this problem, you can use stopSelf(int) to ensure that your request to stop the service is always based on the most recent start request. That is, when you call stopSelf(int), you pass the ID of the start request (the startId delivered toonStartCommand()) to which your stop request corresponds. Then if the service received a new start request before you were able to call stopSelf(int), then the ID will not match and the service will not stop.

  一旦service的任务完成,那么最好是摧毁掉它来省下更多的资源。

  但是有可能会有多个任务需要进行,那么请使用StopSelf(int)的方法并提交最近的任务ID,如果ID配对不上系统便知道还有任务没完成,直到完成为止它才会让系统摧毁掉service。

posted @ 2013-10-20 22:10  yutoulck  阅读(372)  评论(0编辑  收藏  举报