android service 继承IntentService和Service

本文详细介绍了在Android应用中声明和使用服务(service)的方法,包括如何在manifest文件中声明服务,服务的基本概念,以及如何通过intent过滤器启动服务。文章深入探讨了Service和IntentService的区别,提供了从Service类和IntentService类派生的实例代码,展示了如何创建可同时处理多个请求的服务。此外,文章还解释了如何通过onStartCommand()方法处理服务的生命周期和请求,以及如何确保服务的高效运行和性能优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

manifest中声明一个service

  跟activity以及其它组件一样,你必须在你的应用的manifest文件中声明所有的service们.

  要声明你的service,添加一个<service>元素作为<application>元素的儿子.例如:

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

就像一个activity,一个service可以定义intent过滤器来使得其它组件使用明确的intent调用自己.通过声明intent过滤器,你设备上的任意应用中的组件都可以通过给startService()传递匹配的intent来启动你的sevice

  如果你打算只在本应用内使用自己的service,那么你不需指定任何intent过滤器.不使用intent过滤器,你必须使用一个明确指定service的类名的intent来启动你的service

小心: service 默认 运行在声明它的应用进程的主线程中.所以,如果你的 service 执行密集运算或阻塞操作并且与跟用户交互的 activity 位于相同的应用中 ,这个 service 将会拉低 activity 的性能.要避免影响应用的性能,你必须在 service 中启动一个线程.


传统上,有两个类你可以从它派生来创建"启动的"service

  • Service

      这是所有service的基类.当你派生这个类时,在service中创建一个新的线程来做所有的工作是十分重要的.因为这个service会默认使用你的应用的主线程,这将拉低你的应用中所有运行的activity的性能

  • IntentService

      这是一个Service的子类,使用一个工作线程来处理所有的启动请求,一次处理一个.这是你不需你的service同时处理多个请求时的最好选择.你所有要做的就是实现onHandleIntent(),这个方法接收每次启动请求发来的intent,于是你可以做后台的工作.

    ntService类派生

IntentService类派生

  因为大多数"启动的"service不需要同时处理多个请求,可能从IntentService实现你的service是最好的选择.


IntentService做了以下工作:

  • 创建一个默认的工作线程在主线程之外执行所有派发到onStartCommand()intent

  • 创建一个工作队列,某个时间只传递一个intent到你的onHandleIntent()实现中,于是你不必担心多线程的问题.

  • 当所有开始的请求都处理后,停止service,所以你永远不需调用stopSelf()

  • 提供onBind()的默认实现,返回null

  • 提供一个onStartCommand()的默认实现,把intent加入到工作队列之后会传给你的onHandleIntent()实现.

  以上实现使得你可以仅仅实现onHandleIntent()来做要做的工作即可.(当然,你还是要实现一个小小的构造函数)

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

public class HelloIntentService extends IntentService {

  /** 
   * 一个构造函数是必须的,并且你必须调用父类的IntentService(String)以传入工作线程的名字.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * IntentService在默认的工作线程中调用这个方法<p>   *当这个方法返回后,IntentService停止服务,如果能停止的话.
   */
  @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()oronDestroy(),要保证调用父类的对应实现,这样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派生

  如你在上边所见,使用类IntentService使得你实现一个"开始的"service非常容易.然而,如果你需要你的service以多线程方式执行(而不是使用工作队列),那么你需要从类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) {
          // 通常我们在这里做一些工作比如下载一个文件
          // 在我们的例子中,仅仅是睡5秒钟.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // 使用startId停止服务,从而使我们不会在处理
          // 另一个工作的中间停止service
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // 启动运行service的线程.注意我创建了一个
    // 分离的线程,因为service通常都是在进程的
    // 主线程中运行,但我们不想让主线程阻塞.我们还把新线程
    // 搞成后台级的优先级,从而减少对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();

      // 对于每个开始请求,发送一消息来开始一次工作,并且把
      // start 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()返回后杀死了服务,不要重新创建这个service,除非还有挂起的intent需要被传送.这是避免在不必要时运行你的service和当你的应用可以简单重启任何未竟的工作时的最佳选择.

  • START_STICKY

      如果系统在onStartCommand()返回后杀死了这个service,会重新创建这个service并且调用onStartCommand(),但是不再重新发送上次最后一个intent,而是使用一个nullintent调用onStartCommand(),除非有一些挂起的intent,在此情况下,这些挂起的intent被派送.这适合于媒体播放器(or或相似也的服务),它不执行命令,但是无限期的运行并等待一个工作.

  • START_REDELIVER_INTENT

      如果系统在onStartCommand()返回后杀死了service,重新创建这个service并且使用上次最后一个intent调用onStartCommand().任何挂起的intent都顺序地被派送.这适合于活跃地执行一个工作并且应被立即恢复的服务,比如下载一个文件.


转载自 http://blog.youkuaiyun.com/nkmnkm/article/details/7322200

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值