Android Services(服务)

Service是一个应用程序组件,可以在后台执行长时间运行的操作,不提供用户界面。另一个应用程序组件可以启动一个Service,它将继续在后台运行,即使用户切换到另一个应用程序。此外,一个组件可以绑定到一个Service与它交互,甚至执行进程间通信(IPC)。例如,一个Service可能处理网络交易,播放音乐,执行文件I / O,或与一个内容提供者交互,所有的背景。

一个Service基本上可以采取两种形式:

开始(Started)
Service是“开始”,当一个应用程序组件(例如,一个活动)启动它通过调用由startService()。一旦开始,一个Service可以无限期地在后台运行,即使开始它的组件被摧毁。通常,开始Service执行一个操作,不向调用者返回一个结果。例如,它可能通过网络下载或上传文件。当操作完成,服务应该停止本身。
绑定(Bound)
Service是“绑定”当一个应用程序组件绑定到它通过调用bindService()。绑定Service提供了一个客户机-服务器接口,允许组件与Service交互,发送请求,得到结果,甚至跨进程与进程间通信(IPC)。绑定Service只要运行另一个应用程序组件绑定到它。多个组件可以绑定到Service,但是当他们解开,服务被摧毁。

尽管这些文档一般分别讨论了这两种类型的Service,您的Service可以工作,可以开始无限期(运行),也允许绑定。这是简单的你是否实现两个回调方法:onStartCommand()允许组件开始,onBind()允许绑定。
无论您的应用程序启动时,绑定,或者两者兼有,任何应用程序组件可以使用Service(从一个单独的应用程序),以同样的方式,任何组件都可以使用一个activity,通过开始它的意图。然而,您可以声明与私人服务,在清单文件,阻止访问其他应用程序。这一节讨论更多的是关于声明的服务清单。

基础知识 

创建一个Service,你必须创建Service的一个子类(或者它的一个现有的子类)。在你的实现中,您需要覆盖一些回调方法,处理Service生命周期的关键方面,提供了一个组件绑定到Service的机制,如果合适。这些方法你需要重写:

onStartCommand()
系统调用这个方法当另一个组件,比如一个Activity,由callingstartService()要求Service启动。此方法执行后,Service启动,可以在后台运行下去。如果你实现这个,是你的责任是停止Service工作完成后,通过调用stopSelf()或者stopService()。(如果你只是想提供绑定,您不需要实现此方法)。
onBind()
系统调用该方法当另一个组件想绑定的Service(如执行RPC),由callingbindService()。在你实现这种方法,您必须提供一个接口,客户可以使用与Service进行通信,通过返回一个内部。你必须实现这个方法,但是如果你不希望允许绑定,那么您应该返回null。
onCreate()
系统调用此方法在创建服务第一,执行一次性安装程序(之前调用eitheronStartCommand()或onBind())。如果服务已经运行,调用这个方法不能被调用。
onDestroy()
不再使用Service时系统调用此方法,被摧毁了。您的Service应该实现这个清理任何资源,如线程注册侦听器,接收器,等等。这是最后一个调用Service。

如果一个组件通过调用startService()启动Service(它导致调用onStartCommand()),然后服务仍然运行,直到它停止本身stopSelf()或另一个组件停止通过callingstopService()。
如果一个组件调用bindService()创建服务(并且onStartCommand()不被调用),然后服务只要运行组件绑定到它。一旦释放从所有客户服务,系统破坏它。
如果当内存低系统会迫使停止它,活动用户的焦点后才会恢复系统资源。如果服务被绑定到一个活动用户的焦点,那就不太可能被杀,如果声明的服务是运行在前台(稍后讨论),那么它将几乎从未被杀死。否则,如果服务是启动和长期,如果启动你的服务系统会降低它在后台任务列表位置随着时间的推移和服务将成为高度容易杀死,那么你必须设计优雅地处理系统重新启动。如果系统杀死你的服务,一旦资源可用会再次重新启动它(尽管这也取决于你的价值回报fromonStartCommand(),稍后讨论)。更多信息时,系统可能会摧毁一个服务。

在下面几节中,您将看到如何创建每个类型的服务和如何使用它从其他应用程序组件。

声明一个服务清单

就像一个Activity你必须在Manifest文件中声明,一个service也是这样子的。

宣布你的服务,添加一个<service> <application>元素的元素作为一个孩子。例如:

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

还有其他属性可以包含在<service>元素定义属性如权限需要启动服务和服务应该运行的过程。android:name属性是唯一需要的属性,它指定服务的类名。一旦发布您的应用程序,您不应该改变这个名字,因为如果你这样做,你可能会打破一些功能,使用显式意图来引用您的服务(阅读博客,不能改变的事情)。

就像一个活动,一个服务可以定义意图过滤器,允许其他组件调用服务使用隐式意图。通过声明意图过滤器,从任何应用程序组件安装在用户的设备可以开始你的服务如果你声明了一个意图过滤器意图相匹配的另一个应用程序通过由startService()。

如果你打算使用你的服务只有在本地(其他应用程序不使用),那么你不需要(也不应该)提供任何意图过滤器。没有任何意图过滤器,您必须启动该服务使用一个意图,明确服务类名称。关于启动一个服务是下面讨论的更多信息。
另外,您可以确保您的服务是私人应用程序只有如果你包括theandroid:导出属性并将其设置为“false”。这是有效的,即使你的服务供应意图过滤器。

创造一个开始的服务

开始服务,开始通过调用另一个组件由startService(),会导致调用服务的onStartCommand()方法。

当启动一个服务,它有一个独立的生命周期开始它的组件和服务可以无限期地在后台运行,即使开始它的组件被摧毁。因此,服务应该停止本身当它的工作是通过调用stopSelf(),或者另一个组件可以阻止它通过调用stopService()。

应用程序组件,如一个活动可以开始服务通过调用由startService()和通过一个意图,指定服务的服务,包括任何数据使用。服务接收到这个意图onStartCommand()方法。

例如,假设一个活动需要一些数据保存到一个在线数据库。活动可以开始一个同伴服务并把它保存的数据通过一个由startService()的Intent。服务接收到的意图onStartCommand(),连接到互联网和执行数据库事务。当事务完成,服务停止本身,它被摧毁。

传统上,有两个类可以扩展来创建一个启动服务:


Service
这是所有服务的基类。扩展这个类时,重要的是,您创建一个新的线程来做服务的工作,因为该服务使用应用程序的主线程,默认情况下,这可能会减缓任何活动应用程序运行时的性能。  
IntentService
这是一个子类的服务使用一个工作线程来处理所有请求开始,一次一个。这是最好的选择,如果你不需要你的服务同时处理多个请求。所有您需要做的就是实现onHandleIntent(),它接收意图为每个请求,这样你就可以开始做后台工作。

以下部分描述如何实现你的服务使用这些类。

继承IntentService类 

因为最开始服务不需要同时处理多个请求(可以是一个危险的多线程的场景),最好使用IntentService类如果你实现你的服务。

IntentService做以下几点:

1.创建一个默认的工作线程,执行所有的意图传递给onStartCommand()独立于应用程序的主线程。

2.创建一个工作队列,将一个意图传递给你onHandleIntent()的实现,所以你永远不必担心多线程。

3.停止服务毕竟开始请求被处理,所以你不必叫stopSelf()。

4.提供的默认实现onBind()返回null。

5.提供了一个默认实现onStartCommand(),将意图工作队列,然后发送到你onHandleIntent()实现。


所有这一切加起来,所有您需要做的就是实现onHandleIntent()去处理用户给的工作。(虽然,您还需要提供服务的小型构造函数)。

下面是一个实现IntentService的示例:

public class HelloIntentService extends IntentService {

  /** 
   * 构造函数是必需的,而且必须调用父类IntentService(String)构造注入工作线程的名称。
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * IntentService调用这个方法从默认工作线程的Intent开始服务。该方法返回的时候,IntentService停止服务。
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // 我们通常会做一些工作,比如下载一个文件。
      // 对于我们的示例,我们只睡5秒。
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}
这是你所需要的:一个构造函数和onHandleIntent的实现。

如果你决定也覆盖其它回调方法,如onCreate(),onStartCommand(),或onDestroy(),一定要调用父类的实现,以便IntentService能妥善处理工作线程的生命。
例如,onStartCommand()必须返回默认实现(这是意图如何交付给onHandleIntent()):

@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()(但你只需要实现,如果您的服务允许绑定)。    在下一节中,您将看到同样的服务是如何实现的扩展基础服务类的时候,这是一个更多的代码,但这可能是合适的,如果你需要处理并发请求开始。

扩展Service类

当你看到在前面的部分中,使用IntentService使你开始服务的实现非常简单。然而,如果您需要您的服务执行多线程处理开始请求(而不是通过一个工作队列),然后您可以扩展Service类来处理每一个Intent。

相比之下,下面的示例代码是服务类的实现,执行同样的工作使用IntentService上面的例子。为每个请求开始,它使用一个工作线程来执行工作和流程只有一个请求。

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

  //从线程处理程序接收消息
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // 我们通常会做一些工作,比如下载一个文件。
          // 对于我们的示例,我们只休眠5秒。
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          //使用startId停止服务,所以,我们不要停止
          // 服务在处理另一份工作
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
   
    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();

      // 为每个请求开始,发送一个消息开始工作和交付
      // 开始ID,因此我们知道这要求我们停止当我们完成这项工作
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      
      // 如果被杀死在回到这里的之前会被重启
      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()每个调用,你可以同时执行多个请求。这不是这个例子所做的,但是如果这是你想要的,那么你可以为每个请求创建一个新线程,马上运行它们(而不是等待前面的请求完成)。    必须注意,onStartCommand()方法返回一个整数。整数是一个值,描述了系统应该如何继续服务时,系统会杀死它(正如上面所讨论的,默认实现IntentService处理这个为你,尽管你能够修改它)。从onStartCommand()返回值必须是一个常量:

START_NOT_STICKY
如果系统杀死后服务onStartCommand()返回,不要重新创建服务,除非有悬而未决的意图。这是最安全的选择,以避免运行您的服务时没有必要,当您的应用程序可以简单地重新启动任何未完成的工作。
START_STICKY
如果系统杀死后服务onStartCommand()返回,重新创建服务和callonStartCommand(),但不要再交付最后的意图。相反,系统调用onStartCommand()和一个空的意图,除非有悬而未决的意图开始服务,在这种情况下,这些意图。这是适合媒体播放器(或类似服务)不执行命令,但运行下去,等待工作。
START_REDELIVER_INTENT
如果系统杀死后服务onStartCommand()返回,重新创建服务,调用onStartCommand()的最后目的交付服务。交付任何悬而问完成的Intent。这是适合积极执行的服务工作,应立即恢复,如下载一个文件。

开始一个Service

您可以启动一个Service从一个Activity或其他应用程序组件通过一个Intent(指定服务开始)由startService()。Android系统调用服务的onStartCommand()方法并传递它的意图。(你不应该直接调用onStartCommand())。

例如,一个活动可以开始前一节中的示例服务(HelloSevice)使用一个显式意图由startService():

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

startService()方法很快返回结果,Android系统调用Service的sonStartCommand()方法。如果服务没有运行,系统首先调用onCreate(),然后callsonStartCommand()。
如果服务不提供绑定,交付的Intent与由startService()是唯一的应用程序组件之间的通信模式和服务。然而,如果你希望服务发回一个结果,然后启动服务的客户可以为一个广播创建PendingIntent(用getBroadcast())和交付的服务启动的目的服务。服务可以使用广播发表的结果。
多个请求启动相应服务导致多个调用服务的onStartCommand()。然而,只有一个请求停止服务(stopSelf()或stopService())而且必须阻止它。

停止一个服务

对于已启动的服务必须管理它自己的生命周期。也就是说,系统不会停止或破坏服务,除非它必须恢复系统内存和服务持续执行直到onStartCommand()返回。因此,该服务必须通过通过调用stopSelf()停止本身或其他组件可以通过调用stopService()停止它。 

一旦要求用stopSelf或stopService()停止,系统会尽快销毁服务。

然而,如果你的服务同时处理多个请求onStartCommand(),那么你不应该停止服务,当你处理一个请求开始,因为你可能已经收到了新的开始请求(停在第一个请求终止第二个)。为了避免这个问题,您可以使用stopSelf(int),以确保你的请求停止服务总是基于最近的请求开始。也就是说,当你调用stopSelf(int),您传递的ID请求开始(startId送到onStartCommand()),你停止请求对应。如果服务收到了新的开始请求之前你可以叫stopSelf(int),然后ID不匹配,服务不会停止。


创建绑定的Service

绑定服务,允许应用程序组件通过调用bindService()绑定到它来创建一个长期的连接(一般不允许组件通过调用由startService()启动它)。

您应该创建一个绑定服务,通过进程间通信(IPC),当你想与服务交互活动和其他组件在应用程序或向其他应用程序公开您的应用程序的一些功能。

创建一个绑定服务,您必须实现onBind()回调方法返回一个定义的接口内部沟通与服务。其他应用程序组件可以调用bindService()来检索界面,开始调用服务方法。服务只生活服务的应用程序组件绑定到它,所以当没有组件绑定到服务,系统破坏它(你不需要停止绑定服务的方式必须在启动服务时通过onStartCommand())。

创建一个绑定服务,你必须做的第一件事是定义接口,指定客户端如何与服务进行通信。这个接口在服务和客户机之间必须内部的实现,就是你的服务从onBind()回调方法必须返回。一旦客户端接收到的内部,它可以通过该接口与服务交互。

多个客户端可以绑定到服务。当客户端与服务交互,它调用unbindService()来解开。一旦没有客户端绑定到服务,服务系统破坏。

向用户发送通知 

一旦运行,一个服务可以通知用户使用面包通知的事件或状态栏通知。

干杯通知的消息出现在当前窗口的表面了一会儿然后消失,而提供了一个状态栏通知图标在状态栏信息,用户可以选择为了采取行动(如启动一个活动)

通常,一个状态栏通知最好的技术在一些背景工作完成(如文件下载完成),用户现在可以采取行动。当用户选择展开图的通知,通知可以开始一个活动(如查看下载的文件)。

在前台运行服务

一个前台服务是被认为是一个东西服务的用户是主动认识,因而不是候选人为系统杀死内存低的时候。一个前台服务必须提供的通知状态栏,这是摆在“持续”的标题,这意味着该通知不能被解雇,除非这个服务停止或从前景移除。

例如,音乐播放器可以播放音乐从服务应该被设置为在前台运行,因为用户是明确地知道它的操作。在状态栏的通知,可能表明当前歌曲,并允许用户启动一个活动的音乐播放器进行交互。

请求您的服务在前台运行,调用startForeground()。这个方法有两个参数:一个整数,它唯一标识通知和通知的状态栏。例如:

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

删除从前台服务,调用stopForeground()。这个方法取一个布尔值,指示是否取消状态栏通知。这种方法不停止服务。但是,如果你停止服务,它仍然是在前台运行,然后通知也删除。

管理服务的生命周期

Service的生命周期比Activity这更简单的。然而,更重要的是,你密切关注您的服务是如何创建和销毁的,因为服务可以在后台运行,没有用户意识到。

服务生命周期 ——从它创建到它摧毁——可以按照两种不同的路径:

对于已启动的服务
当另一个组件调用的StartService()服务被创建。然后,该服务无限期运行,必须停止本身通过调用stopSelf()。另一个组件也可以通过调用stopService()停止该服务。如果该服务被停止,系统破坏吧。
一个绑定的服务
当另一个组件(客户端)调用bindService()服务被创建。然后,客户端与服务通过的IBinder接口进行通信。客户端可以通过调用unbindService()关闭连接。多个客户端可以绑定到同一个服务,当所有的人解除绑定,系统破坏该服务。 (该服务并不需要停止自己。)


这两个路径并非完全独立。也就是说,您可以绑定到一个服务,已经开始由startService()。例如,背景音乐服务可以开始通过调用由startService()的意图识别音乐演奏。可能后,当用户想要锻炼一些控制球员或当前歌曲的信息,一个活动可以绑定到服务通过调用bindService()。在这种情况下,stopService()或stopSelf()实际上并没有停止服务,直到所有客户解开。

实现生命周期回调 

像一个活动,服务生命周期回调方法,您可以实现监控服务的状态变化,在适当的时间执行工作。以下框架服务演示了每个生命周期的方法:

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
    }
}

通过实施这些方法,您可以监视服务的生命周期的两个嵌套的循环:

1.整个生命周期的服务发生时间之间的onCreate()和时间onDestroy()返回。像一个活动,一个服务的初始设置onCreate()和释放所有剩余资源onDestroy()。例如,音乐播放服务可以创建线程的音乐将在onCreate(),然后停止线程在onDestroy()。

2.onCreate()和onDestroy()方法被称为服务,无论他们是创建bystartService()或bindService()。
服务的活跃的一生始于一个叫onStartCommand()或onBind()。每个方法是把意图,通过由startService()或bindService(),分别为。
如果服务已经启动,活跃的一生结束的同时,整个生命周期结束(服务仍然活跃即使onStartCommand()返回)。如果服务被绑定,活跃的一生结束whenonUnbind()返回。


图说明了服务的典型的回调方法。虽然图分离服务由由startService()从那些由bindService(),记住,任何服务,不管它是如何开始,可能允许客户绑定到它。因此,最初的服务开始withonStartCommand()(由客户机调用由startService())仍然可以接收调用onBind()(当客户端调用bindService())。
有关创建一个服务,它提供了绑定的更多信息,见文档绑定服务,其中包括更多的信息关于onRebind()回调方法中绑定服务的生命周期管理。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值