• Services学习(一)


      对于需要长期运行,例如播放音乐、长期和服务器的连接,即使已不是屏幕当前的activity仍需要运行的情况,采用服务方式。服务将通过API触发启动或者通过IPC(Interprocess Communication)连接请求触发启动。服务将一直运行直至被关闭,或者内存不足时由系统关闭。一般而言,为了节省电量,服务应进行优化减少CPU的消耗和大量网络通信。服务可用于以下的场景:

    1、用户离开activity后,仍需继续工作,例如从网络下载文件,播放音乐
    2、无论activity出现(重现)或离开,都需持续工作,例如网络聊天应用 
    3、连接网络服务,正在使用一个远程API提供的服务 
    4、定时触发的服务,例如Linux中的cron。

    Services主要有两种形式:

      (1)started形式:调用startedservice()启动,需要显式关闭,一般情况下一个service只负责一项操作,不向调用者返回结果。比如从网络上下载文件等。操作完成之后,service应该主动退出。

      (2)Bound形式:其他组件调用bindservice()和此service绑定。

    Service基础:

      一般通过继承Service类来创建一个service,并且需要重写一些重要的方法,这些方法管理service生命周期或者用于其它组件绑定此服务,主要有以下方法:

      onstartCommand():当其它组件(比如一个Activity)调用startService()时,系统调用onstartCommand()。这个方法调用后,service在后台开启,要结束这个service,必须自己调用stopself()或者其它组件调用stopService()。

      onBind():当其他组件调用bindService()绑定这个服务时,系统调用onBind()。这个方法中必须包含一个返回IBinder,用于服务和客户端通信的接口。

      onCreate():当service第一次被创建时调用,在onstartCommand()和onBind()之前被调用。

      onDestory():service()关闭时调用,释放资源,结束相关线程。

    在manifest文件中声明service:

      <service>元素作为<application>元素的子项 

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

    创建Started类型的service

      其它组件调用startService()启动service,系统随之调用service的onstartCommand()。service一旦启动,必须自己调用stopSelf(),或者其它组件调用stopService()才能结束它。

      其它组件可以通过startservice()传递一个携带着数据的Intent给service,service端在onstartCommand()中接收传递过来的Intent。

    一般情况下,可以通过继承以下两个类来创建service:

      Service:这种Service默认使用程序的主线程,使用时最好自己创建一个新线程来处理服务工作。

      IntentService:它是Service的子类,使用一个工作线程来处理请求,但是每次只能处理一个请求,不能同时处理多个请求。它需要实现onHandleIntent()方法来接收intent,处理客户端请求。

    通过继承IntentService类创建:

    IntentService的工作流程如下:

    • 创建一个独立于主线程的的工作线程,执行传递给onstartCommand()的Intent。  
    • 创建一个工作队列,每次传递一个Intent给onHandleIntent()。
    • 所有请求被处理完后,Service会自动退出,不需要显式调用stopself()。
    • 默认提供的onBind()返回null。
    • onstartCommand()将Intent发送给一个工作队列,然后交给onHandleIntent()处理。

    注意:需要实现onHandleIntent()方法和Service的构造器

    继承IntentService的例子:

    public class HelloIntentService extends IntentService {
    
      /**
       * 需要一个构造器, 必须调用父类构造器 IntentService(String)
       * 并传入要创建的工作线程的名字
       */
      public HelloIntentService() {
          super("HelloIntentService");
      }
    
      /**
       *  IntentService在工作线程中调用这个方法
       *  此方法返回后, IntentService关闭Service
       */
      @Override
      protected void onHandleIntent(Intent intent) {
          //一般情况下,我们在此做一些操作,比如下载一个文件。
          //对于这个例子,我们只是让线程睡眠5s
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
      }
    } 

      如果需要重写其它方法,比如:onCreate(),onstartCommand(),或者onDestroy(),一定要先调用父类实现,这样IntentService才能正确处理工作线程的生命周期。

      比如,onstartCommand()必须返回默认实现(它表示怎样将Intent传递给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在允许被绑定时才需要实现它。

    通过继承Service类创建

      如果你需要创建一个Service来执行多线程的操作(而不是通过工作队列依次响应客户端的请求),你可以通过继承Service类来创建。

      下面是用继承Service类的方式创建服务的代码,代码执行的操作和上面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();
      }
    }

    很显然,这种方式要比使用IntentService麻烦一些。

      但是,这种方式下可以为每个请求分别创建一个工作线程(上面代码没有这样做),这样多个请求就可以被同时执行(而不是要等上一个请求完成后才能执行下一个请求)。

      从上面代码中我们注意到,onStartCommand()方法返回一个整型常量。系统根据返回的这个常量来决定一个Service被杀死后怎样来回复它。常量有以下三种:START_NOT_STICKY,不重新创建Service,除非还有新的Intent要传递给它;START_STICKY,重新创建Service并调用onStartCommand(),但是不向它传递之前的Intent,调用onStartCommand()时向它传递null作为Intent。新的Intent可以传递给它;START_REDELIVER_INTENT,重新创建Service并调用onStartCommand(),向onStartCommand()传递之前的Intent,新的Intent也会依次传递给它。

    启动一个Service

      可以在一个Activity或者其它组件中调用带有Intent参数的startService()来启动一个Service。然后系统就调用Service的onStartCommand()方法并把Intent传递给它。

    例如: 

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

    关闭一个Service:

      Service必须管理自己的生命周期,系统不会主动关闭或者销毁一个Service(除非极少数情况下系统内存不足并且Service的onStartCommand()方法已经返回)。Service可以通过调用stopself()来关闭自己,其它组件可以调用stopService()来关闭某个服务。

      但是,如果你的Service正在处理多个请求,当你完成一个请求时不能马上关闭Service,因为这时很有可能Service又接收到了一个新的请求并且准备处理。为了避免这种情况,你可以使用stopSelf(int),参数是你要关闭的请求的ID,如果已经有新的请求被接收,那么要关闭的请求ID和新接收的请求的ID不同,Service将不会被关闭。

    创建一个BoundService

      Bound Service就是其它组件调用bindService()和一个Service绑定起来,从而创建一个持久的通信。

      创建bound Service时,

  • 相关阅读:
    11个网站后台模版 | Admin Dashboards | Bootstrap
    Replace Pioneer
    Unity扩展编辑器--类型3:Custom Editors
    Unity扩展编辑器--类型1:Editor Windows
    Android新项目GBSS:第1篇 搭建开发环境
    树莓派(jessie)制作服务并开机启动
    Jqgrid动态拖拽
    看得见的百亿脱贫投入,看不见的阿里技术“脱贫代码”
    OceanBase迁移服务:向分布式架构升级的直接路径
    支付宝工程师创造出了一个可以“拷贝”支付宝的神器
  • 原文地址:https://www.cnblogs.com/sage-blog/p/4053025.html
Copyright © 2020-2023  润新知