Android服务部分总结

Service是一个可以在后台执行长时间运行操作而不需要提供用户操作界面的应用组件,服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行,组件可以绑定到服务,与之进行交互,甚至执行进程间的通信。

服务基本上分为两种形式:

启动------Activity通过调用startService()启动服务时,服务即处于“启动”状态,一旦启动,服务可以在后台无限期运行,即使启动服务的组件被销毁也不受影响,已启动的服务通常是执行单一操作,且不会将结果返回调用方,例如下载或者上传,当操作完成时,服务自行停止。

绑定------Activity通过调用bindService()绑定服务时,服务即处于“绑定”状态,绑定服务提供了一个客户端服务器接口,允许组件与服务进行交互,发送请求,获取结果,利用进场间通信跨进程执行操作。仅当与另一个应用组件绑定时,绑定的服务才会运行,多个组件可以同时绑定到该服务,但全部取消后,服务即被销毁。

注意,两种方式可以同时运行,即可以启动服务,又可以绑定,问题在于是否实现了一组回调方法onStartCommand()和onBind()。

无论应用是处于启动还是绑定,或者绑定且启动状态,都可以像使用Activity那样通过调用Intent使用服务,不过,可以通过清单文件将服务声明为私有,并阻止其他应用访问。

注意,服务在其托管进程的主线程中运行,既不创建自己的线程,也不在单独的进程中运行,这意味着,如果服务将执行任何CPU密集型工作或者阻止性操作,应在服务内创建新线程来完成该工作,通过使用单独的线程,可以降低“应用无响应”(ANR)错误的风险,而应用主线程仍可以继续专注于用户与Activity之间的交互。


创建服务

创建服务,必须创建Service的子类或者使用一个已有子类,需要重写一些回调方法,以处理服务生命周期的某些关键方面并提供一种机制将组建绑定到服务,应重写的回调方法有:

onStartCommand()---当另一个组件通过调用startService()请求启动服务时,系统将调用此方法,一旦执行此方法,服务就会启动并有可能后台无限运行,若实现此方法,在服务工作完成后,需要通过调用stopSelf()或stopService()来停止服务。

onBind()---当另一个组件通过调用bindService()与服务绑定时,系统将调用此方法,在实现此方法中,必须通过返回IBinder提供一个借口,供客户端与服务器通信。若不希望允许绑定,应返回null

onCreate()---首次创建服务时,将调用此方法来执行一次性设置,在调用onStartCommand()或onBind()之前。

onDestroy()---当服务不在使用且被销毁时,系统调用此方法,服务实现此方法,清理所有资源,这是服务接受的最后一个调用。

如果组件通过调用startService()启动服务,这会导致onStartCommand()的调用,则服务将一直运行,知道服务使用stopSlelf()自行停止运行,或由其他组件通过调用stopService()停止为止。

如果组件是通过调用bindService()来创建服务且未调用onStartCommand(), 则服务只会在该组件与其绑定时运行,一旦服务与所有客户端之间的绑定全部取消,系统便会销毁它。


在清单文件中声明服务

为确保应用安全,一定始终使用显示Intent启动或绑定Service,且不为服务声明Intent过滤器。可以添加android:exported属性,设置为”false“,确保服务仅适用于此应,可以有效阻止其他应用启动这项服务。


创建启动服务

Service---适用于所有服务的基类,扩展此类时,必须创建一个用于执行所有服务工作的新线程,因为默认时,服务将使用应用的主线程,这回降低应用正在运行的所有Activity的性能。

IntentService---这是Service的子类,使用工作线程逐一处理所有启动请求。只需要实现onHandIntent()方法即可,该方法会接受每个启动请求的Intent。

扩展IntentService类

大多数启动服务都不必同时处理多个请求,因此,使用IntentService类实现服务也许是最好的选择。

IntentService执行以下操作:

*创建默认的工作线程,用于在应用的主线程外执行传递给onStartCommand()的所有Intent。

*创建工作队列,用于将Intent逐一传递给onHandIntent()实现,这样不必担心多线程的问题。

*在处理完所有启动请求后停止服务,故不必调用stopSelf()。

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

*提供onStartCommand()的默认实现,可将Intent依次发送到工作队列和onHandleIntent()实现。

综上所述,只需事先onHandleIntent()来完成客户端提供的工作即可。

以下是IntentService的实现实例:

public class HelloIntentService extends IntentService {
  public HelloIntentService() {
      super("HelloIntentService");
  }
  @Override
  protected void onHandleIntent(Intent intent) {
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
      }
  }
}
只需一个构造函数和一个onHandleIntent()实现即可。

如果还要重写其他回调方法(如onCreate(), onStartCommand(), onDestroy())确保调用超类实现,以便IntentService能够妥善处理工作线程的生命周期。

扩展服务类

使用IntentService显著简化了启动服务的实现,但是若要求服务执行多线程,而不是通过工作对联处理启动请求,则可扩展Service类来处理每个Intent。
以下是提供了Service类实现的代码,执行的工作与上述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) {
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
          }
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    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();
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      return START_STICKY;
  }

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

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}
由于是自己处理onStartCommand()的每个调用,故可以同时执行多个请求,可以为每个请求创建一个新线程,然后立即运行这些线程。注意,onStartCommand()方法必须返回整型,整型是一个值,用于描述系统应该如何在服务终止的情况下继续运行服务,返回的值必须是以下常量之一:

START_NOT_STICKY----最安全的选项

START_STICKY---适用于不执行命令但无限期运行并等待作业的媒体播放器

START_REDELIVER_INTENT---适用于主动执行应该立即恢复的作业(如:下载)

启动服务:

可以通过将Intent传递给startService(),从Activity或其他应用组件启动服务,Android系统调用onStartCommand()方法,并向其传递Intent。注意,切勿直接调用onStartCommand()。

如,Activity可以结合使用显示Intent与startService()启动服务:

Intent intent = new Intent(this, HelloService.class);
startService(intent);
startService()方法立即返回,且Android系统调用服务的onStartCommand()方法,如果服务尚未运行,则系统先调用onCreate(),然后调用onStartCommand()。多个服务启动请求,会导致多次对服务的onStartCommand()调用,但停止只需一次服务停止调用(stopSelf()或stopService()).

停止服务

启动服务必须管理自己的生命周期,即除非系统必须回收内存资源,否则系统不会停止或销毁服务,故服务必须通过调用stopSelf()来自行停止运行,或者另一个组件通过调用stopService()来停止。

调用stopSelf(int)传递与停止请求对应的ID服务,指定停止对应ID的服务,若stopService()会停止全部服务。

创建绑定服务

绑定服务允许应用组件通过调用bindService()与其绑定,以便创建长期连接,通常不允许组件通过调用startService()来启动。

要创建绑定服务,必须实现onBind()回调方法以但会IBinder,用于定义与服务通信的接口。然后其他Activity可以调用bindService()来检索该接口,并开始对服务调用方法,若没有组件绑定到服务,系统会自动销毁该服务。服务于客户端之间的接口必须是IBinder的实现,且服务必须从onBind()回调方法返回,一旦客户端收到IBinder,即开始通过该接口与服务进行交互。多个客户端可以同时绑定到服务,客户端完成与服务的交互后,会调用unbindService()取消绑定,一旦没有客户端与服务绑定,则系统会销毁掉服务。
向用户发送通知

服务可以使用Toast通知或状态栏通知来通知用户所发生的事件。通常,状态栏通知是最好的。

在前台运行服务

前台服务即使在内存不足时,系统也不会终止,必须在状态栏提供通知,除非服务停止或被移除,否则不能清除通知。

让服务运行在前台,需调用startForeground()采用两个参数,唯一标识通知的整型数和状态栏的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_ID, notification);
注意,startForeground()的整型ID不得为0

若要从前台移除,调用stopForeground()采用一个布尔值,指示是否也移除状态栏通知,此方法不会停止服务,但如果在服务正在前台运行时将其停止,则通知也会被移除。

管理服务生命周期:

服务的生命周期比Activity生命周期简单,但更应密切关注如何创建和销毁服务。

服务生命周期有两条路径:

启动服务:在Activity调用startService()时创建,然后无限运行,必须通过调用stopSelf()来自行停止运行。其他组件也可以调用stopService()来停止服务。服务停止后,系统将其销毁。

绑定服务:服务在客户端调用bindService()时创建,然后客户端通过IBinder接口与服务进行通信。客户端可以通过调用unbindService()关闭连接,多个客户端可以绑定到相同的服务,但所有绑定都取消后,系统自动销毁服务。

这两条路径并非完全独立,可以绑定到已经使用startService()启动的服务,例如,可以通过使用Intent调用startService()来启动后台服务,之后Activity可以通过调用bindService()绑定到服务,除非所有客户端都取消绑定,否则stopService()或stopSelf()不会停止服务。

服务生命周期的回调:

与Activity类似,可以实现服务生命周期的回调方法来监控服务状态或添加执行工作。

public class ExampleService extends Service {
    int mStartMode;       //表明如果服务销毁时行为
    IBinder mBinder;      //绑定客户端的接口
    boolean mAllowRebind; //表明重新绑定是否应该被绑定

    @Override
    public void onCreate() {
        //服务被创建
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //开始服务,因为调用了startService()方法
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        //一个客户端正在调用bindService()绑定到服务
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        //全部客户端通过调用unbindService()取消绑定 
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        //一个客户端正在调用bindService()绑定到服务
        //在onUnbind()被调用后
    }
    @Override
    public void onDestroy() {
        //服务不在被使用且被销毁后
    }
}


服务的有效生命周期从调用onStartCommand()或onBind()开始,每种方法均由Intent对象,分为传递到startService()或bindService(),启动服务的有效生命周期与整个生命周期同时结束,绑定服务的有效生命周期在onUnbind()返回时结束。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值