zoukankan      html  css  js  c++  java
  • android Services(服务)

    Service 是应用组件,能够在后台长时间运行,而且没有界面。其他的应用组件能够启动service和它能继续在后台运行,即使用户切换到其他的应用。此外,component 能够与service绑定,并且与service进行交互,甚至是在进程间通信。例如,service可能处理网络事务,播放音乐,处理文件,或者是与content provider 交互,这些操作都是在后天做的。

    Service 基本上有两种形式:

    Started
    当应用中的组建通过调用startService()方法启动service,Service 处于启动做状态. Service 启动后, 它可以无限期的在后台运行,即使启动它的组建已经销毁了。通常,service 处理一个动作,并且不会返回结果给调用者。例如,service 可能在处理下载,上传文件,当操作完成,service应该自动停止。
    Bound
    当应用中的组建通过bindService()方法启动service,这个Service处于绑定状态,绑定的service提供接口允许组建与之交互,发送请求,获取结果,甚至可以在进程之间可以完成。一个绑定的service运行时间与绑定它的组建相关,当所有绑定它的组建都取消绑定时,service也会销毁。 

    不管你的应用是否启动,绑定service,或者两者都有,任何的应用组建可以使用这个服务(即使在其他的应用中),同样的,任何的组建可以使用activity,通过Intent启动。当然,service可以在manifest文件中被定义为私有的,不允许从其他的应用中访问。

    Caution: 一个服务运行在主线程的托管流程-service不会创建自己的Thread, 并且不会运行在其他的进程中(除非指定)。这个意思就是说,如果你的服务是打算做任何CPU密集型工作或阻塞操作(如MP3播放或网络) , service必须是在一个新的线程中完成工作.通过使用不同的线程,需要减少ANR(Application Not Responding)错误风险,应用程序的主线程可以继续致力于和你的activities进行交互。

    The Basics


    为了创建一个新的service,需要继承自Service,或者Service的子类。在实现的过程中, 需要重写一些回调函数,这些回调函数包含service的主要过程,需要重写的方法包括:

    onStartCommand()
    The system calls this method when another component, such as an activity, requests that the service be started, by callingstartService(). Once this method executes, the service is started and can run in the background indefinitely. If you implement this, it is your responsibility to stop the service when its work is done, by calling stopSelf() orstopService(). (If you only want to provide binding, you don't need to implement this method.)
    onBind()
    The system calls this method when another component wants to bind with the service (such as to perform RPC), by callingbindService(). In your implementation of this method, you must provide an interface that clients use to communicate with the service, by returning an IBinder. You must always implement this method, but if you don't want to allow binding, then you should return null.
    onCreate()
    The system calls this method when the service is first created, to perform one-time setup procedures (before it calls eitheronStartCommand() or onBind()). If the service is already running, this method is not called.
    onDestroy()
    The system calls this method when the service is no longer used and is being destroyed. Your service should implement this to clean up any resources such as threads, registered listeners, receivers, etc. This is the last call the service receives.

    如果组建通过调用startService()(这个过程会调用startService()),这个service一直运行直到它自己调用stopSelf()或者其他的组建调用stopService(),才能够停止运行。

    如果组建通过调用bindService()创建一个Service(onStartCommand()不会被调用,onBind()会调用),这个service的生命周期与绑定的它的的组建相同,当没有组建绑定这个service,service将会销毁自己。

    android系统在内存低的时候会销毁service.当一个service绑定了一个这在操作的activity时,这个service被销毁的概率会更小,如果这个service被声明为在前台运行,这样的service几乎不会被杀死。除非,这个service运行了很长的时候,系统会降低它在后台tasks列表里面的地位,这样这个service就会变得很容易杀死, 这样就需要一个很好的设计,重新启动系统。如果系统杀死了你的service,在资源重新可用的时候service必须启动足够快的 (though this also depends on the value you return fromonStartCommand(), as discussed later). 

    在manifest中声明service

    和其他的组建一样,service也必须在manifest文件中声明。

    声明service, 增加 <service> 元素,作为 <application> 节点的子节点. 例如:

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

    在 <service>元素中还有其他的一些属性,例如定义需要权限启动service和service运行在那个进程中。 android:name 是唯一需要声明的属性. 当你发布您的应用的时候, 不能够改变它的名字.

    和activity一样,service可以定义intent filters, 允许其他的组建通过明确指定filter调用。通过定义intent filters, 任何安装在用户手机上的组建都有可能启动你的服务,如果声明的intent filter 与从其他的应用中发送的intent相符,那么service 就会启动。

    如果你想你的service只能在本应用程序上使用,那么不能提供任何的intent filters。 没有intent filters, 启动service就必须使用service name.

    补充,可以通过设置android:exported="false",确保service只能在当前应用中使用。即使 提供了intent filters, 都没有用。

    Creating a Started Service


    通过调用startService()方法启动service,onStartCommand()方法会调用。

    当service启动,它的生命周期不依赖于启动它的组建,service 能在后端无限的运行,当启动它的组建销毁了,它同样还是会继续运行。这样的话,service 做完了任务的之后,通过调用stopService()应该停止自己, 或者是其他的组建通过调用stopService()方法停止它。

    应用中的组建可以启动service,比如activity,通过调用startService() 或者是通过Intent(指定详细的filter)A.这样service在onStartCommand()中收到Intent

    举个例子, 假如一个activity需要把数据保存到网络数据库中。activity 可以启动一个service,通过Intent把数据传递给这个service,这个service 收到在onStartCommand()方法中收到intent,连接网络,保存数据,当保存完毕,service停止并销毁自己。

    习惯上, 有两个类可以继承实现Service:

    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.

    Extending the IntentService class

    因为最开始服务不需要同时处理多个请求 (which can actually be a dangerous multi-threading scenario), 继承IntentService实现自己的service可能是最好的方式。

     IntentService 做了以下工作:

    • 创建一个默认的工作线程中执行所有递给onStartCommand()的意图传,这个目的是为了与应用主线程区分。
    • 创建一个队列,这样可以保证在某一点时间上,只会处理一个Intent,永远不用担心多线程.
    • 处理完所有的请求时,会自动的停止service。不用调用stopSelf().
    • 提供onBind()的默认实现,返回null
    • 提供onStartCommand()默认的实现,发送Intent到队列里面, 然后在onHandleIntent() 方法里面实现。

    客户端只需要实现onHandleIntent()方法。

    实现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) {
                  }
              }
          }
      }
    }

    这是你要做的所有工作:一个构造函数和实现onHandleIntent().

    如果你决定重写其他的回调函数,比如 onCreate()onStartCommand(), 或者onDestroy(),确保要调用父类的实现,这样onHandleIntent()才能正确的处理工作线程的生命周期.

    例如, onStartCommand() 必须调用父类的实现:

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

    除了onHandleIntent(), 还有一个不需要调用父类实现的方法是onBind()(这个方法在绑定的情况下才需要重写).

    Extending the Service class

    如果您需要在service里面处理多线程,可以继承Service类,处理每一个Intent。

    为了比较, 下面的例子代码实现Service,处理和上面例子中一样的工作。

    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(); 
      }
    }

    这个工作量比使用IntentService要大很多。

    然后,因为你要处理每一个请求,你可以同时处理多个请求。上面的例子不是同时处理多个请求,如果你想处理多个请求,可以为每一个请求创建一个线程,然后正确的处理每一个请求。

    主意,onStartCommand()方法必须返回一个整数。这个整数的值代表的意思是,当系统杀死service时,service该以什么形式启动这个service。返回值必须是下面常量之一:

    START_NOT_STICKY
    If the system kills the service after onStartCommand() returns, do not recreate the service, unless there are pending intents to deliver. This is the safest option to avoid running your service when not necessary and when your application can simply restart any unfinished jobs.
    START_STICKY
    If the system kills the service after onStartCommand() returns, recreate the service and callonStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job.
    START_REDELIVER_INTENT
    If the system kills the service after onStartCommand() returns, recreate the service and callonStartCommand() with the last intent that was delivered to the service. Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as downloading a file.

    Starting a Service

    启动一个service可以通过在activity中发送Intent的方式实现。android 系统通过Intent调用service的onStartCommand()方法。(不能直接调用 onStartCommand().)

    例如, activity能用Intent的方式启动service,与上面(HelloService)达到的效果是一致的:

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

     startService()会立刻返回,android 系统调用service的onStartCommand()方法。如果指定的service没有被启动过,系统会先调用onCreate()方法,然后调用onStartCommand()方法.

    如果service没有提供绑定,Intent 只能通过startService()方法与应用组建通信。然而,如果让一个service能够返回值,客户端启动service,会创建一个PendingIntent,这个PendingIntent是为了广播, 并且把它用Intent传递给service。然后service才能用广播传递结果。

    多个请求启动service,调用相应的onStartCommand()获得返回值。但是,仅仅只需要一个请求停止service(调用stopSelf() 或者stopService()).

    Stopping a service

    运行状态的必须管理它自己生命周期。正常情况,系统是不会停止和销毁service的,service 在onStartCommand()方法返回之后,还是会运行,除非系统需要回收系统内存. 因此,service 必须自己停止自己,通过调用stopSelf() 或者是其他的组件通过调用stopService().

    当调用stopSelf() 或者stopService(),系统会快速的销毁service。

    然后,如果service 在onStartCommand()方法中同时处理多个请求,service在处理请求的过程中不能停止它,因为,在停止的时候,一个新的请求已经启动(在停止第一个请求的时候,有可能会停止第二个请求). 为了避免这个问题,可以使用stopSelf(int)  . 意思说, 当调用 stopSelf(int), 通过传递请求ID(startId 是被传递给onStartCommand())到service里,停止响应的请求.然而,当service在stop(调用stopSelf(int))之前, 收到了一个新的请求,那么这个ID与之前的那个不相符,service就不会停止。

    Caution: 当service做完了工作,非常重要的一点是停止service,目的是为了避免让非系统资源和消耗电能。还可以通过在其他的组件中停止service,调用stopService().甚至可以绑定特定的service,如果service曾经接到一个请求(call onStartCommand()),你必须主动停止服务.

    Creating a Bound Service


    有些service允许其他的组件通过绑定的方式(call bindService)绑定它,为了创建一个长期运行的连接(通常它不允许其他的service调用startService()方法启动它).

    创建绑定的service,是为了activities,还有其他的组件能够与它交互,或者是暴露应用的中一些方法给其他的应用(通过IPC).

    创建一个绑定的service,必须重写onBind()方法,返回一个IBinder.其他的应用组建能够通过调用bindService()获得bind接口,然后就可以调用service上的方法了。这样的service只服务于与它有绑定关心的组件,因此,当没有组件绑定这个service的时候,系统就会销毁它(不需要主动调用停止service的方法, 除非是通过调用onStartCommand()方法启动的服务).

    创建一个绑定服务的第一件事是定义一个指定的接口,这个的是保证service和client通信的。这个接口用在service和client之间的前提是,必须实现IBinder接口(这个接口是onBind()中返回值)。一旦client收到这个IBinder对象,client就可以通过这个接口和service通信。

    多个客户端可以同时与一个service绑定。当一个client做完了任务之后,client需要调用unbindService()解除绑定关心。当没有一个client与这个service绑定时,系统会销毁这个服务。

    这里有多种方式实现一个绑定的service,这个实现过程比启动运行一个service更加复杂,因此绑定service在Bound Services 中详细介绍。

    Sending Notifications to the User


    当service处于运行状态时,service能够通过Toast Notifications 和 Status Bar Notifications通知用户。

    A toast notification 是显示在当前窗口之上的一个消息(显示时间很短,然后消失), 然而 a status bar notification 在状态栏上会提供图标和文字信息.

    通常,当一些后台任务完成的时候(such as a file completed downloading) status bar notification 是最好的提示技术,用户还可以操作它。当用户从expanded view 中选中通知,通知能启动一个activity(下载文件的view)。

    Running a Service in the Foreground


    前台服务被认为是用户主动意识,并且不容易会被系统回收的服务。 前台服务必须提供通知到状态栏, 它提示系统service不会被销毁,除非service停止了或者是从前台移除了。

    例如,在服务中播放音乐,这个服务要设置为前台服务,因为用户要清楚知道音乐播放的状态。这个通知栏可以明确显示当前歌曲和启动运行的activity(与音乐播放器交互的).

    为了请求service运行在前端,调用startForground(). 这个方法需要两个参数:一个整数(唯一定义通知)和Notification 对象。例如:

    Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
            System.currentTimeMillis());
    Intent notificationIntent = new Intent(this, ExampleActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    notification.setLatestEventInfo(this, getText(R.string.notification_title),
            getText(R.string.notification_message), pendingIntent);
    startForeground(ONGOING_NOTIFICATION, notification);

    为了从前端移除service,调用stopForeground().这个方法需要一个boolean参数,为了移除状态通知栏。这个方法不会停止service。当停止前端service,通知也同样会删除。

    Note: startForeground() and stopForeground() 在Android 2.0 (API Level 5)中介绍. 在更老的版本中,为了让service运行在前端,用setForeground().

    Managing the Lifecycle of a Service


    service 的生命周期比activity的更简单。但是,在使用service的时候必须多注意service如何启动和如何关闭,因为service能过在用户不知道的情况下在后台一直运行着。

    service的生命周期-从创建到销毁-有两种不同的方式:

    • A started service

      The service is created when another component calls startService(). The service then runs indefinitely(无限制) and must stop itself by calling stopSelf(). Another component can also stop the service by callingstopService(). When the service is stopped, the system destroys it..

    • A bound service

      The service is created when another component (a client) calls bindService(). The client then communicates with the service through an IBinder interface. The client can close the connection by callingunbindService(). Multiple clients can bind to the same service and when all of them unbind, the system destroys the service. (The service does not need to stop itself.)

    这两种方式并非完全分开的。可以绑定一个service,这个service已经通过调用startService()方法启动。例如, 可以通过调用startService()发起一个Intent启动音乐service。之后,用户有可能想控制播放器或者获取有关歌曲的信息,一个activity可以通过bindService() 的方式绑定service。这种情况下,stopService()或者stopSelf()方法不再能够停止service,直到所有的绑定解除了之后,才能真正的停止这个服务。

    Implementing the lifecycle callbacks

    与activity相同,service同样有生命周期回调函数。这些方法中可以做些监听,并且在正确的时间做任务。下面的例子简单介绍了这些生命周期方法:

    public class ExampleService extends Service {
        int mStartMode;       // indicates how to behave if the service is killed
        IBinder mBinder;      // interface for clients that bind
        boolean mAllowRebind; // indicates whether onRebind should be used
    
        @Override
        public void onCreate() {
            // The service is being created
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // The service is starting, due to a call to startService()
            return mStartMode;
        }
        @Override
        public IBinder onBind(Intent intent) {
            // A client is binding to the service with bindService()
            return mBinder;
        }
        @Override
        public boolean onUnbind(Intent intent) {
            // All clients have unbound with unbindService()
            return mAllowRebind;
        }
        @Override
        public void onRebind(Intent intent) {
            // A client is binding to the service with bindService(),
            // after onUnbind() has already been called
        }
        @Override
        public void onDestroy() {
            // The service is no longer used and is being destroyed
        }
    }

    Note: 与activity不同的是,在service的回调函数中不用调用父类的函数.

    Figure 2. The service lifecycle. The diagram on the left shows the lifecycle when the service is created withstartService() and the diagram on the right shows the lifecycle when the service is created with bindService().

    通过实现这些方法,可以监控service生命周期中的两个内部循环:

    Note: Although a started service is stopped by a call to either stopSelf() or stopService(), there is not a respective callback for the service (there's no onStop() callback). So, unless the service is bound to a client, the system destroys it when the service is stopped—onDestroy() is the only callback received.

    Figure 2 illustrates the typical callback methods for a service. Although the figure separates services that are created by startService() from those created by bindService(), keep in mind that any service, no matter how it's started, can potentially allow clients to bind to it. So, a service that was initially started withonStartCommand() (by a client calling startService()) can still receive a call to onBind() (when a client calls bindService()).

    For more information about creating a service that provides binding, see the Bound Services document, which includes more information about the onRebind() callback method in the section about Managing the Lifecycle of a Bound Service.

  • 相关阅读:
    用SNMP协议实现系统信息监控--Windows Server 2008
    Apache与Tomcat区别联系
    Oracle数据库的创建与验证
    oracle监听服务开启
    【VS Code 开发工具】在VS Code中使用Markdown语法
    【SQLServer数据库】SQLServer分库分表
    【SQLServer数据库】SQLServer死锁与优化
    【SQLServer数据库】SQLServer悲观锁和乐观锁
    【HTTP】HTTP Body
    【SQLServer数据库】SQLServer视图
  • 原文地址:https://www.cnblogs.com/java20130722/p/3207357.html
Copyright © 2011-2022 走看看