Android | Service

news2024/11/28 10:53:53

Android Service

Service 概念

实现程序后台运行的解决方案,一种可在后台执行长时间运行操作而不提供界面的应用组件。Service 的运行不依赖于任何用户界面,即使程序被切换到后台,或者用户打开了另外一个应用程序,Service 仍然能够保持正常运行。Service 并不是运行在一个独立的进程当中的,而是依赖于创建 Service 时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的 Service 也会停止运行。实际上 Service 并不会自动开启线程,所有的代码都是默认运行在主线程当中的,我们需要在 Service 的内部手动创建子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞的情况。

Android 多线程

当需要执行一些耗时操作,比如发起一条网络请求时,考虑到网速等其他原因,服务器未必能够立刻响应我们的请求,如果不将这类操作放在子线程里运行,就会导致主线程被阻塞,从而影响用户对软件的正常使用。

Android多线程编程Java多线程编程 使用的语法大致相同,当然也有些许区别。

Android 的UI是线程不安全,如果想要更新应用程序里的 UI元素,必须在主线程中进行,否则就会出现异常。如果需要使用耗时的子线程的结果来更新相应的UI控件,,需要借助异步消息处理机制。

异步消息处理机制

Android 中的异步消息主要由四部分构成:

  • Message:在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间传递数据。
  • Handler:主要用于发送和处理消息的。发送消息一般是使用 HandlersendMessage() 方法、 post() 方法等,而发出的消息经过一系列地辗转处理后,最终会传递到 HandlerhandleMessage() 方法中。
  • MessageQueue:主要用于存放所有通过 Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个 MessageQueue 对象。
  • Looper:每个线程中的 MessageQueue 的管家,调用 Looperloop() 方法后,就会进入一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息时,就会将它取出,并传递到 HandlerhandleMessage() 方法中。每个线程中只会有一个 Looper 对象。

异步消息的处理流程:首先需要在主线程当中创建一个 Handler 对象,并重写 handleMessage() 方法。然后当子线程中需要进行UI操作时,就创建一个 Message 对象,并通过 Handler 将这条消息发送出去。之后这条消息会被添加到 MessageQueue 的队列中等待被处理,而 Looper 则会一直尝试从 MessageQueue 中取出待处理消息,最后分发回 HandlerhandleMessage() 方法中。由于 Handler 的构造函数中我们传入了 Looper.getMainLooper(),所以此时 handleMessage() 方法中的代码也会在主线程中运行,然后便可以在此更新 UI。一条Message经过以上流程的辗转调用后,也就从子线程进入了主线程,从不能更新UI变成了可以更新UI。

AsyncTask

除了使用异步消息处理机制,还可以借助 AsyncTask 工具。 AsyncTask 是对异步消息处理机制的一种封装。是一个抽象类,必须创建一个子类去继承,包含三个泛型参数:

  • Params:在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
  • Progress:在后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
  • Result:当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

需要重写的方法主要有以下几个:

  • onPreExecute():这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
  • doInBackground(Params...):这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成,就可以通过 return语句 将任务的执行结果返回,如果 AsyncTask 的第三个泛型参数指定的是 Unit ,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用 publishProgress (Progress...) 方法来完成。
  • onProgressUpdate(Progress...):当在后台任务中调用了 publishProgress(Progress...) 方法后,onProgressUpdate (Progress...) 方法就会很快被调用,该方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
  • onPostExecute(Result):当后台任务执行完毕并通过 return语句 进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据进行一些UI操作,比如说提醒任务执行的结果,以及关闭进度条对话框等。

Service 生命周期

在这里插入图片描述

一旦在项目的任何位置调用了 ContextstartService() 方法,相应的 Service 就会启动,并回调 onStartCommand() 方法。如果这个 Service 之前还没有创建过, onCreate() 方法会先于 onStartCommand() 方法执行。 Service 启动了之后会一直保持运行状态,直到 stopService()stopSelf() 方法被调用,或者被系统回收。注意,虽然每调用一次 startService() 方法, onStartCommand() 就会执行一次,但实际上每个 Service 只会存在一个实例。所以不管你调用了多少次 startService() 方法,只需调用一次 stopService()stopSelf() 方法,Service 就会停止。

另外,还可以调用 ContextbindService() 获取一个 Service 的持久连接,这时就会回调 Service 中的 onBind() 方法。类似地,如果这个 Service 之前还没有创建过,onCreate() 方法会先于 onBind() 方法执行。之后,调用方可以获取到 onBind() 方法里返回的 IBinder 对象的实例,这样就能自由地和 Service 进行通信了。只要调用方和 Service 之间的连接没有断开,Service 就会一直保持运行状态,直到被系统回收。

当调用了 startService() 方法后,再去调用 stopService() 方法。这时 Service 中的 onDestroy() 方法就会执行,表示 Service 已经销毁了。类似地,当调用了 bindService() 方法后,再去调用 unbindService() 方法, onDestroy() 方法也会执行

Service 用法

每一个 Service 都需要在 AndroidManifest.xml 文件中进行注册才能生效。

可以通过将 Intent 传递给 startService()startForegroundService(),从 Activity 或其他应用组件启动服务。Android 系统会调用服务的 onStartCommand() 方法,并向其传递 Intent,从而指定要启动的服务。

除非必须回收内存资源,否则系统不会停止或销毁服务,并且服务在 onStartCommand() 返回后仍会继续运行。服务必须通过调用 stopSelf() 自行停止运行,或由另一个组件通过调用 stopService() 来停止它。

绑定服务允许应用组件通过调用 bindService() 与其绑定,从而创建长期连接。此服务通常不允许组件通过调用 startService() 来启动它。如要创建绑定服务,您需通过实现 onBind() 回调方法返回 IBinder,从而定义与服务进行通信的接口。服务只用于与其绑定的应用组件,因此若没有组件与该服务绑定,则系统会销毁该服务。不必像通过 onStartCommand() 启动的服务那样,以相同方式停止绑定服务。

  • 前台服务:会有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,类似于通知的效果。即使用户停止与应用的交互,前台服务仍会继续运行。视为处于前台的应用应当具有可见 Activity ,或具有前台 Service ,或另一个前台应用已关联到该应用。
  • 后台服务:后台服务执行用户不会直接注意到的操作。Android 8.0 开始系统不允许后台应用创建后台 Service,需要迁移方案去做处理。

Android 8.0 开始,只有当应用保持在前台可见状态的情况下,Service 才能保证稳定运行,一旦应用进入后台之后,Service 随时都有可能被系统回收。从 Android 9.0 系统开始,使用 前台Service 必须在 AndroidManifest.xml 文件中进行权限声明。如果处于后台时,应用需要创建一个前台 Service,使用 startForegroundService() 方法,而非 startService()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/166587.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3——第十五章(计算属性:computed)

一、基础示例 模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。推荐使用计算属性来描述依赖响应式状态的复杂逻辑。 在这里定义了一个计算属性 publishedBooksMessage。computed() 方…

【设计模式】创建型模式·原型模式

设计模式学习之旅(五) 查看更多可关注后查看主页设计模式DayToDay专栏 一. 概述 用一个已经创建的实例作为原型,通过复制(克隆)该原型对象来创建一个和原型对象相同的新对象。 原型模式包含如下角色: 抽象原型类:规定了具体原型对象必须实现…

Java基础(二)

1.标识符标识符:由数字、字符、下划线、$组成(不能以数字、下划线开头)java严格区分大小写2.命名规范包名:多单词组成时所有字母全部小写类名、接口名:多单词组成时,所有单词首字母大写变量名、方法名&…

屏幕录制工具哪个好用?分享3款相见恨晚的软件

在我们的日常生活中,我们经常使用截图和手机屏幕记录功能来记录一些重要的内容。然而,录制的图片清晰度很低,或者需要不断的截图,这很容易出错一些重要的内容,这个时候就需要进行录屏了。那么电脑上的屏幕录制工具哪个…

group by详解

group by功能 在SQL中group by主要用来进行分组统计,分组字段放在group by的后面;分组结果一般需要借助聚合函数实现。 group by语法结构 1、常用语法 语法结构 SELECT column_name1,column_name2, … 聚合函数1,聚合函数2 , … FROM table_name GROUP…

电脑删除了大文件怎么恢复?看看这四种方法

电脑能够帮助我们存储大量的文件,比如视频、文档、音频等,但是随着时间的流逝,有些文件所存在的意义也变得毫无价值了,这时候很多小伙伴都会选择删除操作,可是由于电脑磁盘内容过多,容易面临重要文件被误删…

硬件仿真加速器与原型验证平台

基于软件仿真工具对于动辄几百万门的ASIC验证而言,几乎显得力不从心。不管是从成本还是从性能的角度来看,使用硬件仿真器或者基于FPGA的原型验证平台,几乎是验证工程师的不二法门。因为基于硬件的环境能够极大的提高验证的速度,增…

Promise(基础)

Promise是什么 1.promise是一门新的技术(ES6规范) 2.Promise是JS中一编程的解决方案(旧的解决方案是单纯的使用回调函数) 3.promise一个构造函数,promise队形用来封装一个一步操作并可以获取其成功/失败的结果值。 注…

sparksql案例实操

sparksql案例实操解决语句如下 select * from( select , rank()over(partition by area order by clickCnt desc) from(select area, product_name, count()as clickCnt from( select a.*, p.product_name, c.area, c.city_name from user_visit_action a join product_info p…

Dubbo与Spring集成

Dubbo框架常被当作第三方框架集成到应用中,当Spring集成Dubbo框架后,为什么在编写代码的时候,只用了DubboReference注解就可以调用提供方的服务了呢?这篇笔记就是分析Dubbo框架是怎么与Spring结合的。 现状integration层代码编写…

关于嵌入式学习和规划,求指点?

在知乎上收到的一个提问问题:各位大佬好,我先说说基本情况,28岁,北京,嵌入式软开,军工行业。硕士毕业一年半。工作不忙收获很少,造成我自己特别迷茫,没有了方向,自己学没…

【C++】Hash闭散列

目录 一、哈希的概念 1.1 哈希冲突 1.2 哈希函数 1.3 装载因子 二、闭散列 2.1 线性探测 2.2 Insert 插入 2.3 Find 查找 2.4 Erase删除 2.5 插入复杂类型 2.6 二次探测 三、源代码与测试用例 3.1 hash源代码 3.2 测试用例 一、哈希的概念 在前面学习了二叉搜索…

多巴胺聚乙二醇多巴胺,Dopamine-PEG-Dopamine简介,多巴胺是具有正性肌力活动的单胺化合物

产品名称:多巴胺聚乙二醇多巴胺,双多巴胺聚乙二醇(Dopamine-PEG-Dopamine) 中文别名:多巴胺PEG多巴胺,双多巴胺聚乙二醇 英文名称:Dopamine-PEG-Dopamine 存储条件:-20C&#xff0…

磨金石教育影视技能干货分享|浅析中国CG特效的发展现状

中国CG特效的发展2015年是一个分水岭。在2015年之前,中国CG 特效发展是混乱的,不成熟的。总体表现就是技术水平不足,缺少人才培养的体系。当时从事CG的公司,大概有两个类型:“技术型与业务型”。所谓技术型的公司&…

设计模式_结构型模式 -《装饰器模式》

设计模式_结构型模式 -《装饰器模式》 笔记整理自 黑马程序员Java设计模式详解, 23种Java设计模式(图解框架源码分析实战) 概述 我们先来看一个快餐店的例子。 快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜…

PowerDesigner设计表时显示注释列Comment

首先,使用 PowerDesigner 新建模型,File —> New Model 然后,切换到模型类型(Model types)选项卡,选中 Physical Diagram 然后点击右侧表格图标,在左侧面板中创建表格如下。双击表格,找到Columns选项卡…

招标采购中,如何编写有效的RFI(信息邀请书)?

在企业招标采购过程中,RFI(信息邀请书)是一个从商品或服务的潜在供应商处收集信息的正式流程。RFI旨在由客户编写并发送给潜在供应商。RFI通常是第一个也是最广泛的一系列请求,旨在缩小潜在供应商候选人名单。 当企业对潜在供应…

【实际开发07】- XxxxController 批量处理 × 5 -【model】

目录 1. Mode 1. IotTypeController 基础 7 tips 2. 辅助添加 Validated 无法覆盖的 参数校验 1. 预处理空指针异常 ( 校验 : 核心必填参数 not null ) 3. RequestBody 对应API 存在 feign 调用时 , 注意 : 不可缺省 1. feign API 需要加 RequestBody , Controller 层可…

手工测试 | 黑盒测试方法论—边界值

本文节选自霍格沃兹测试学院内部教材 边界值分析法是一种很实用的黑盒测试用例方法,它具有很强的发现故障的能力。边界值分析法也是作为对等价类划分法的补充,测试用例来自等价类的边界。 这个方法其实是在测试实践当中发现,Bug 往往出现在定…

OpenCV4.6 VS 4.7 QRCode解码功能效果对比

导 读 本文主要对OpenCV4.7.0和4.6.0中QRCode检测/解码功能做简单的测试对比,供大家参考。 背景介绍 最近OpenCV更新到了4.7.0版本,在ChangeLog算法部分除了新增Stackblur滤波算法(详细介绍见下面链接),还有对QRCode检测和解码的改进。 吊打…