我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android创建服务之started service详细介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android创建服务之started service详细介绍

创建started service

       应用组件(例如Activity)调用startService()来启动一个Service,将需要的参数通过Intent传给Service,Service将会在onStartCommand函数中获得Intent。

有两种方式可以创建started service,一种是扩展Service类,另外一种是扩展IntentService类

扩展Service
       这是所有服务的基类。扩展这个类的时候,特别重要的一点是,需要创建一个新的线程来做服务任务,因为service默认是运行在你的主线程(UI线程)中的,它会使你的主线程运行缓慢。

扩展IntentService
       这是一个service的子类,他可以在一个工作线程中处理所有的启动请求。如果你不需要同一时刻出来所有的服务请求,使用IntentService是一个很好的选择。你需要做的仅仅是实现onHandlerIntent()方法,通过这个函数处理接受的每一个启动请求。


下面我们学习如何扩展IntentService类和Service类

扩展IntentService类

IntentService做了什么?
1.创建一个独立于主线程的工作线程,用于执行通过onStartCommand()传来的所有的intent。
2.创建一个工作队列,将接受的所有intent一个一个的传给onHandlerIntent(),所以同一时间内你只处理一个intent,不用担心多线程的问题。
3.当所有的请求都处理完后,停止服务,所以你不需要手动调用stopSelf()。
4.提供onBind()函数的默认实现,返回null
5.提供onStartCommand()函数的默认实现,它把intent发送到工作队列中去,然后工作队列再发送到你的onHandlerIntent()函数中。

有了上面的基础,你仅仅要做的就是实现onHandlerIntent()。并且实现一个小小的构造函数。

参考下面的例子:

代码如下:
public class HelloIntentService extends IntentService {

 
  public HelloIntentService() {
      super("HelloIntentService");
  }

 
  @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) {
              }
          }
      }
  }
}

如果你要实现其他的回调函数,例如 onCreate , onStartCommand ,onDestroy 一定记得调用父类相应的函数,这样IntentService才能正确的处理工作线程。

例如,你需要在onStartCommand函数中弹出一个提示,那么你可以这样写:
代码如下:
@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);
}

有一点例外的是,如果你需要其他组件绑定服务,那么你的onBind函数不需要调用父类的onBind。

在下一节中,你将会看到通过扩展service类来实现与本节相同的服务,所不同的是代码会更多,但是同样意味着更灵活,特别是你需要同时处理多个请求时,比较适合直接扩展Service。

扩展Service类

如同你在上一节看到的一样,使用IntentService来实现一个started service非常简单。如果你需要你的service来执行多个线程,那么你需要扩展Service类去处理每个intent。

作为对比,下面的例子用Service类实现了和上一节中一样功能的服务。

代码如下:
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(),所以你可以在同一时间处理多个请求。这个例子没有这样做,但是如果你愿意,你完全可以每收到一个请求的时候,创建一个新线程并且立即运行,而不是等到上一个请求处理完成后再运行。

注意,onStartCommand()函数必须返回一个整数。这个整数描述了当系统杀死该服务时将要如何处理该服务。返回值必须是下面几个值:
START_NOT_STICKY
在onStartCommand()返回后,系统杀死服务,服务将不会重启,除非有pending intents(目前笔者还不懂什么是pending Intents)要投递。这比较适合非常容易就可以重新启动未完成任务的情况。

START_STICKY
        在系统杀死服务后,重启服务并且调用onStartCommand(),但是不重新投递上一次的intent。系统会传给onStartCommand()函数null,除非有pending intent来启动服务,会传给onStartCommand()相应的intent。这种做法比较适合媒体播放服务,不需要执行命令,但是独立运行,常处于等待任务的服务。

START_REDELIVER_INTENT
在系统杀死服务后,重启服务并且调用onStartCommand(),参数传入上一次的intent,然后接下来是pending intent传入onStartCommand()。这比较适合于正在执行一项工作,它不能被立刻恢复,例如下载文件。

启动Service

你可以从一个Activity或者其他组件调用startService(intent)来启动服务。Android系统会调用服务的onStartCommand()函数并且传给它intent。

用上一节的HelloService来做个例子:
Intent intent = new Intent(this, HelloService.class);
startService(intent);
startService()会立刻返回,Android系统会调用服务的onStartCommand()函数。如果这是服务没有在运行,系统会首先调用onCreate()函数,然后会紧接着调用onStartCommand()函数。

如果服务没有提供绑定,那么通过startService()函数传入的intent就是应用组件和服务进行交互的唯一途径。如果你想服务发送结果给客户组件,那么客户组件需要在启动服务时,创建一个用于广播的PendingIntent,通过intent投递给服务。这样,服务就可以利用广播把结果发送给客户组件。

多个请求会导致服务的onStartCommand()被调用多次。但是,只需要一个停止请求(stopSelf() 或 stopService())就会使服务停止。

停止服务

一个启动的服务必须管理自己的生命周期。因为除非系统需要回收资源的时候,系统不会停止或者销毁服务。所以,服务必须通过调用stopSelf()来停止自己,或者有其他组件调用stopService()。

一担收到stopSelf()或stopService()的停止请求,系统会立刻销毁服务。

如果你的服务同时处理多个服务请求,当某个请求完成时就不能马上停止服务,因为你可能已经又接受了一个新的请求(在第一个请求完成时结束服务会终止第二个请求)。为了解决这个问题,你可以调用stopSelf(int)函数来保证你的停止请求总是基于最近的一次服务请求。这是因为,调用stopSelf(int)函数
会把onStartCommand()函数传入的startId传给停止请求。当你的startId和最近一次接受的服务请求不匹配时,服务不会结束。

注意:stopSelf(int)函数只是简单的与最近一次收到的startId比较,如果你的服务处理过程是多线程的,可能后收到的服务请求先完成,那stopSelf(int)的方案不适合你,你应该手动管理接受到的服务请求和完成的服务,比如在onStartCommand()函数中把startId记录到一个表中,在完成服务任务时在表中记录完成状态,在确保表中任务都完成的情况下直接调用stopSelf()来停止服务。

在前台运行服务

一个前台服务是用户能够很明显意识到的服务,当可用内存比较低的时候,系统不会杀掉前台服务。一个前台服务必须提供一个状态栏通知,放在正在运行条目里,这意味着只要服务没有停止或者一直是前台服务,这个通知就不会被消失。

举个例子,一个音乐播放器服务应该被设置为前台运行,因为用户非常明显知道他在运行。这个状态栏通知可以显示正在播放的歌曲,并且可以允许用户点击进入音乐播放界面。

要使服务运行在前台只要调用startForeground()。这个方法有两个参数:一个通知的整数ID和一个状态栏通知。代码片段:
代码如下:
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);

使用stopForeground()函数可以把服务从前台移除。这个函数带一个布尔值参数,来表示是否从状态栏移除通知。这个函数不会使服务停止。如果把前台服务停止掉,那么通知也会同时被移除。

您可能感兴趣的文章:Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路Android Service 服务不被杀死的妙招android开发教程之开机启动服务service示例Android中实现开机自动启动服务(service)实例Android中Service(后台服务)详解Android四大组件之Service(服务)实例详解Android 通过webservice上传多张图片到指定服务器详解Android Service服务详细介绍及使用总结Android 判断某个服务(service)是否运行Android实现在ServiceManager中加入自定义服务的方法详解


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android创建服务之started service详细介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android创建服务之started service详细介绍

创建started service 应用组件(例如Activity)调用startService()来启动一个Service,将需要的参数通过Intent传给Service,Service将会在onStartCommand函数
2022-06-06

Android Service服务详细介绍及使用总结

Android Service服务详解 一.Service简介 Service是android 系统中的四大组件之一(Activity、Service、BroadcastReceiver、 ContentProvider),它
2022-06-06

腾讯云服务器搭建Jenkins详细介绍

目录一、连接腾讯云服务器二、环境准备三、Jenkins部署四、Jenkins安装一、连接腾讯云服务器 1.Mac:(以ssh连接为例) 注意:IP地址为公网地址ssh 用户名@IP地址2.Windonws连接:详细说明 二、环境准备 第一步
2022-06-04

如何在阿里云搭建ecs服务器?详细介绍

在数字化时代,搭建一个可靠的服务器对于企业或个人来说非常重要。阿里云作为国内最大的云计算平台,拥有丰富的服务器资源,让搭建服务器变得非常简单。本文将详细介绍如何在阿里云搭建ecs服务器。一、登录阿里云账号首先,你需要在阿里云官网上注册一个账号。注册完成后,登录你的阿里云账号。二、购买ecs服务器在阿里云控制台,选
如何在阿里云搭建ecs服务器?详细介绍
2023-11-06

阿里云轻量服务器搭建SSR是否可用?详细介绍

随着互联网技术的快速发展,SSR(服务器端渲染)已经成为了现代网站构建的一个重要技术。然而,有一些用户可能会遇到这样的问题:他们的阿里云轻量服务器在没有网络的情况下是否还可以搭建SSR呢?本文将详细介绍如何在阿里云轻量服务器上搭建SSR,并解答这个问题。阿里云轻量服务器是一种经济型服务器产品,主要面向个人开发者、
阿里云轻量服务器搭建SSR是否可用?详细介绍
2023-12-16

阿里云服务器关闭休眠功能的详细介绍与使用建议

随着互联网技术的发展,服务器作为网络基础设施的作用日益凸显。在使用服务器的过程中,如何有效地管理和优化服务器资源,减少服务器的闲置和浪费,是广大用户关注的问题。本文将详细解析阿里云服务器关闭休眠功能,并提出使用建议。一、什么是阿里云服务器关闭休眠功能?阿里云服务器关闭休眠功能是阿里云服务器提供的一项服务,主要目的
阿里云服务器关闭休眠功能的详细介绍与使用建议
2023-12-09

阿里云服务器IP公有和私有哪个好一点?详细介绍及选择建议

阿里云服务器IP公有和私有是两种常见的服务器类型,各有优缺点。本文将详细介绍这两种类型,并给出选择建议。阿里云服务器IP公有和私有哪个好一点?阿里云服务器IP公有和私有两种类型各有优缺点,选择哪种更好,主要取决于您的需求和预算。公有IP服务器:公有IP服务器是阿里云提供的一种服务器类型,用户可以通过互联网访问服务
阿里云服务器IP公有和私有哪个好一点?详细介绍及选择建议
2023-12-13

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录