【Android学习笔记】偷摸持久运行的Service

一、What is a service ?

Service作为Android的四大组件之一,往往执行一些后台的耗时操作,比如网络下载上传、媒体播放、IO操作、与content provider交互等等。Service可以分为两大类,其一:开启服务之后即自己运行自己的,往往没有返回结果,不需要与activity交互,这类服务叫做started;其二:需要与activity交互,形成一个C/S的交互模式,比如更新界面等等,这类服务叫做bound。

二、How to create it ?

与其它四大组件类似,往往需要继承Service类(或者某些Service的子类,比如IntentService),并重写某些生命周期方法。其中几个比较重要的生命周期方法如下:
1.onCreate:往往进行一次性配置工作,比如创建子线程(因为service默认运行在主线程中,如果执行某些耗时的操作,会出现ANR),此方法只会执行一次。
2.onStartCommand:此方法会在activity调用startService之后执行,bindService不会执行此方法,主要进行一些主要的逻辑的处理,执行完成后往往需要进行stopSelf结束服务。为了方便操作,我们往往使用IntentService。
3.onBind:服务的开启方式为bindService时,会执行此方法。此时返回一个binder对象(继承自Binder,在service中采用内部类的方式实现,与activity交互的代理),然后在activity中实现ServiceConnection接口(往往采用内部类),并重写其中onServiceConnected和onServiceDisconnected方法,获取binder对象,进行交互。
4.常见的创建方式
<span style="font-size:14px;">public class HelloIntentService extends IntentService {

  /** 
   * 构造方法是必需的,必须用工作线程名称作为参数
   * 调用父类的[http://developer.android.com/reference/android/app/IntentService.html#IntentService(java.lang.String) 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) {
              }
          }
      }
  }
}</span>

<span style="font-size:14px;">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() {
    // 启动运行服务的线程。
    // 请记住我们要创建一个单独的线程,因为服务通常运行于进程的主线程中,可我们不想阻塞主线程。
    // 我们还要赋予它后台运行的优先级,以便计算密集的工作不会干扰我们的UI。
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    
    // 获得HandlerThread的Looper队列并用于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) {
      // 我们不支持绑定,所以返回null
      return null;
  }
  
  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); 
  }
}</span>


三、lifecycle




四、其他

1、关于onStartCommand的返回值
START_NOT_STICKY 
如果系统在onStartCommand()返回后杀死了服务,则不会重建服务了,除非还存在未发送的intent。 当服务不再是必需的,并且应用程序能够简单地重启那些未完成的工作时,这是避免服务运行的最安全的选项。
START_STICKY 
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并调用onStartCommand(),但不会再次送入上一个intent, 而是用null intent来调用onStartCommand() 。除非还有启动服务的intent未发送完,那么这些剩下的intent会继续发送。 这适用于媒体播放器(或类似服务),它们不执行命令,但需要一直运行并随时待命。
START_REDELIVER_INTENT 
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并用上一个已送过的intent调用onStartCommand()。任何未发送完的intent也都会依次送入。这适用于那些需要立即恢复工作的活跃服务,比如下载文件。
2、有一件事我们需要明确,那就是每一个服务只会有一个实例,比如我有如下执行过程startService、startService、stopService、stopService,分析如下,第一次调用startService会有oncreate-->onStartCommand,第二次调用startService则只会执行onStartCommand,接下来调用stopService,则服务销毁,第二次执行stopService不会起作用,但也不会出现异常(服务只会调用一次onCreate)。
3.startService和bindService是可以同时时候用的,比如有如下执行过程startService、bindService,则需要注意的是在销毁服务的时候需要依次执行unbindService,stopService。例如,一个后台音乐服务可以通过调用startService()来启动,传入一个指明所需播放音乐的 Intent。 之后,用户也许需要用播放器进行一些控制,或者需要查看当前歌曲的信息,这时一个activity可以通过调用bindService()与此服务绑定。在类似这种情况下,stopService()stopSelf()不会真的终止服务,除非所有的客户端都解除了绑定。
4.前台服务,通过使用startForeground+Notification类可以参考http://blog.csdn.net/yyingwei/article/details/8509402
5.使用Messenger和AIDL进行IPC
6.参考文献
官方文档
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值