当前位置: 首页 > article >正文

Android - 服务 Service

前台20s后台200s不执行玩就报ANR异常。一、概念没有界面在后台长期运行在主线程中的一个组件后台运行的功能如果不放在 Service 里如在单例工具类里音乐播放器APP切出去容易被系统回收。1.1 Service 类型后台服务start()启动服务执行一些不会被用户注意到的操作。从 Android 8 (API26) 开始当 APP 处于后台时系统会对后台服务的运行施加限制。bind()绑定服务前台服务startForeground()执行一些对用户可见的操作播放音频必须显示通知。如果应用的所有 Activity 对用户都不可见并且应用未运行任何前台服务则表示该应用在后台运行1.1 与线程的区别ServiceThread可以配置执行在不同的进程中。CPU调度的最小单位。任何有Context的地方都可以控制Service当Activity销毁后不再持有该Thread的引用不管该子线程是一次任务还是循环任务都无法再控制。三、属性配置/权限声明官方前台服务类型和权限声明说明service android:name.MyService //Service的类名 android:label //Service的名字若不设置默认为Service类名 android:icon //Service的图标 android:permission //申明此Service的权限有提供了该权限的应用才能控制或连接此服务 android:process //表示该服务是否在另一个进程中运行远程服务)不设置默认为本地服务remote则设置成远程服务 android:foregroundServiceTypelocation|camera //前台服务类型Android9引入未声明会在调用 startForeground() 时抛异常MissingForegroundServiceTypeException android:enabledtrue //是否默认启动默认为 true android:exportedfalse //该服务是否能够被其他APP启动默认为true intent-filter android:priority1000 / //配置优先级最大1000 /service//前台服务必须声明此项 uses-permission android:nameandroid.permission.FOREGROUND_SERVICE/ //依照具体业务权限申请对应权限 uses-permission android:nameandroid.permission.FOREGROUND_SERVICE_CAMERA/四、后台服务startService() 启动服务bindService() 绑定服务使用场景启动一个后台服务长期执行某个任务。生命周期和Activity绑定。外部需要与服务通讯调用服务中的方法。公开接口供客户端远程调用绑定时才会执行。生命周期onCreate→onStartCommand→onDestroyonCreate→onBind→onUnbind→onDestroy多次开启只有第一次会创建服务每次都执行onStartCommand。只有第一次会创建服务同一个组件多次调用无效果不同组件调用会将多个组件绑定到该服务。多次关闭只需要调用一次就可以全部解绑。全部组件都解绑后服务才会被销毁。4.1 生命周期所有和界面相关生命周期都没有。系统会因为内存不足而销毁Service是可以等到内存充足后再重建Service并执行onStartCommand()。onStartCommand()return super.onStartCommand(intent, flags, startId)return Service.START_NOT_STICKY默认情况被销毁后不会重建。return Service.START_STICKY被销毁后会重建。但是不再保存onStartCommand()中的形参intent。return Service.START_REDELIVER_INTENT被销毁后会重建。会将销毁钱最后一次传入onStartCommand()中的Intent保留。4.2 startService() 启动服务长期后台运行不会因为APP或者Activity销毁而停止但服务进程在内存不足时会被回收外部不能调用Service里的方法。每调用一次 startService()onStartCommand() 就会执行一次但实际上每个 Service 只会存在一个实例。所以不管调用了多少次 startService()只需调用一次 stopService() 或 stopSelf() 就会停止。stopSelf() 是 Service 内部自己调用的。class MyService : Service() { //第一次创建的时候才调用 override fun onCreate() { super.onCreate() } //每次启动的时候都会调用 override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { return super.onStartCommand(intent, flags, startId) } //销毁的时候调用 override fun onDestroy() { super.onDestroy() } } Activity { //开启和关闭不要用同一个intent当退出Activity后开启的intent就是null关闭调用报错。 //实际开发开启和注销服务都写在Activity的onStart()、onDestroy()里面就没有这个问题 btn1.setOnClickListener { val intent Intent(this, MyService::class.java) startService(intent) //启动服务 } btn2.setOnClickListener { val intent Intent(this, MyService::class.java) stopService(intent) 停止服务 } }4.3 bindService() 绑定服务生命周期和Activity同生共死外部可以调用Service中的方法可以和多个Activity绑定共享。隐形的服务系统设置里面查不到Activity死的时候Service也死了不能长期在后台运行。bindService()绑定服务会调用onCreate() onBind()unbundService()解绑服务会调用onUnbind() onDestroy()。绑定后再绑定无效果解绑后再解绑抛异常因此写到Activity的onCreate()和onDestroy()中。Binder是可以用作Service和Client之间通信无论Service和Client是否在同一个进程内Binder都可以完成Service和Client之间的通信。//抽取用于暴露Service中供外部调用的功能 interface IFunction { fun callEat() fun callJump() } class MyService : Service() { //绑定时调用 override fun onBind(intent: Intent): IBinder { return MyBinder() //返回代理人实例供外部Client与Service通讯 } //解绑时调用 override fun onUnbind(intent: Intent?): Boolean { return super.onUnbind(intent) } //再次绑定时调用 override fun onRebind(intent: Intent?) { super.onRebind(intent) } //销毁的时候调用 override fun onDestroy() { super.onDestroy() } //Service中自定义的函数 fun eat() {} fun jump() {} //定义代理人在代理人中提供调用Service的对应方法 inner class MyBinder : Binder(), IFunction { override fun callEat() { eat() } override fun callJump() { jump() } } } Activity { private lateinit var function: IFunction private val connection object : ServiceConnection { //绑定时调用 override fun onServiceConnected(name: ComponentName, binder: IBinder) { //抽取成属性供别处调用 function binder as IFunction //转为抽取的接口对象来调用Service暴露的功能 } //解绑时调用 override fun onServiceDisconnected(name: ComponentName) {...} } btn1.setOnClickListener{ val intent Intent(this, MyService::class.java) bindService(intent, connection, Context.BIND_AUTO_CREATE) //绑定Service } btn2.setOnClickListener{ val intent Intent(this, MyService::class.java) unbindService(connection) //解绑Service } btn3.setOnClickListener{ function.callJump() //就可以调用Service里的方法了 function.callEat() } }4.4 混合方式既长期在后台运行又能调用 Service 里面的方法。在 Activity 的 onCreate() 中 startService() 并 bindService()顺序无所谓。在 Activity 的 onDestroy() 中 unbindService()根据情况在需要的地方stopService()顺序无所谓两者都调用才会销毁服务。startService() 后不管是否有 Activity 进行 bindService() 或 unbindService()Service都在后台运行着直到调用 stopService() 或 stopSelf() 才会关闭或者系统资源不足时被杀死。五、进程间通信 AIDL详见Android 进程Aidl接口描述语言专门用来解决调用远程服务的方式。调用第三方支付中APP中的付款功能要将支付信息传递过去①用隐式意图开启到对方ServiceIntent intent new Intent();intent.setAction(cn.hugmua.demo.remote);bindService(intent,conn,BIND_AUTO_CREATE);②远程应用中把暴露出来的接口Iservice.java改成Iservice.aidl删除public权限修饰(public是包和包之间而现在用于多个工程之间)③远程应用中自定义的MyBinder只继承Stub。在gen目录里生成了新的Iservice.java里面的Stub帮我们继承了Binder和实现了Iservice④本地应用中创建和远程服务中相同包名并把Iservice.aidl复制过来gen目录下会自动生成相应报名文件夹里面有Iservice.java⑤本地应用中在连接器ServiceConnection的onServiceConnected()中调用Stub静态方法anInterface()将IBinder转换为Iservicepublic void onServiceConnected(ComponentName name, IBinder service) {iservice Stub.anInterface(service);}⑥现在就可以用iservice对象调用远程服务里的方法了要处理异常。六、前台Service保活官方介绍从Android 8.0 (API26) 开始只有APP保持在前台可见状态的情况下 Service 才能保证稳定运行一旦进入后台 Service 随时都有可能被系统回收防止恶意APP长期在后台占用手机资源。因此需要 Service 能一直保持运行状态就可以使用前台Service。前台Service在状态栏里会显示图标下拉通知栏有显示通知。必须显示通知这样就让用户清楚得知道什么APP占用着资源前台Service优先级较高不会由于系统内存不足而被回收后台Service优先级较低当系统出现内存不足情况时很有可能会被回收。uses-permission android:nameandroid.permission.FOREGROUND_SERVICE /从Android 9.0系统开始必须在 Manifest 中进行权限声明。override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { //构建点击通知后打开MainActivity的Intent对象 val myIntent Intent(this, MainActivity::class.java) val pendingIntent PendingIntent.getActivity(this, 0, myIntent, 0) //构建通知 val notification Notification.Builder(this, ) //获取构建器 .setContentTitle(标题) //设置通知的标题 .setContentText(内容) //设置通知的内容 .setSmallIcon(R.mipmap.ic_launcher) //设置状态栏小图标 .setLargeIcon(R.mipmap.ic_launcher) //设置通知栏大图标 .setContentIntent(pendingIntent) //设置点击通知后的操作 .build() //构建一个通知 //让Service变成前台Service并在系统的状态栏显示出来 startForeground(1, notification) //参数一唯一标识停止的时候还要用参数二通知 return super.onStartCommand(intent, flags, startId) } override fun onDestroy() { super.onDestroy() stopForeground(1) //开启时设置的唯一标识 }6.1 版本变更与适配官方变更说明Android 9 (API 28)引入 foregroundServiceType 权限使用前台服务必须声明 FOREGROUND_SERVICE 权限否则抛出 SecurityException。还需要根据服务类型Android 10 (API 29)如果前台服务使用了定位必须声明 “location”。Android 11 (API 30)如果前台服务使用了相机或麦克风必须声明 “camera”“microphone”。Android 12 (API 31)应用在后台运行时不得启动前台服务少数情况除外详见。Android 14 (API 34)必须根据前台服务类型在 AndroidManifest 中申请对应的服务权限未申请对应的权限会报错 SecurityException。Android 15 (API35)从后台启动前台服务更严格前台服务运行时长进行限制。七、耗时任务推荐使用 WorkManager详见七、IntentService 已废弃在 Android11API30已废弃。普通 Service 默认运行在主线程耗时操作需要开启子线程。Service一旦启动就会一直运行直到调用 stopService()、stopSelf() 或被系统回收我们可能会忘记调用。IntentService 用于创建一个异步任务执行完会自动停止的Service某些情况下可能不是你希望的行为尤其是需要持续运行的服务它的 onHandleIntent() 执行在单独的子线程中与普通Service相同的生命周期方法仍运行在主线中所有通过 startService() 发送的 Intent 都会在这个子线程中按顺序处理一次只能执行一个Intent可能导致延迟。class MyService : Service() { override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { thread { //耗时任务 stopSelf() //停止Service } return super.onStartCommand(intent, flags, startId) } } class MyIntentService : IntentService(MyIntentService) { //传入的字符串随意只在调试的时候有用 override fun onHandleIntent(intent: Intent?) { //耗时任务 } override fun onDestroy() { super.onDestroy() Log.d(MyIntentService, 有自动停止) } }八、JobIntentService 已废弃在 Android12API31已废弃。原本用于在 Android8API26中替代 IntentService版本自适应在Android5还是IntentService以便在后台执行任务时兼容 JobScheduler。然而随着 Android 对后台任务的管理越来越严格如电池优化、应用待机等以及 WorkManager 的成熟和普及JobIntentService 也逐渐被淘汰。创建一个类继承自 JobIntentService重写 onHandleWork() 来处理后台任务使用 enqueue() 来启动服务。class MyService : JobIntentService() { override fun onHandleWork(intent: Intent) { //耗时任务(可通过action区分任务类型) when (intent.action) { 下载 - {} } } } val intent Intent(this, MyService::class.java).apply { setAction(下载) putExtra(url, www.baidu.com) } //jobId填入唯一值就行 JobIntentService.enqueueWork(this, MyService::class.java, 1, intent)

相关文章:

Android - 服务 Service

前台20s后台200s不执行玩就报ANR异常。 一、概念 没有界面在后台长期运行在主线程中的一个组件,后台运行的功能如果不放在 Service 里(如在单例工具类里音乐播放器),APP切出去容易被系统回收。 1.1 Service 类型 后台服务 start…...

造相Z-Image模型v2传统艺术风格专题:水墨、版画与油画的数字重生

造相Z-Image模型v2传统艺术风格专题:水墨、版画与油画的数字重生 当千年传统艺术遇见现代AI技术,会碰撞出怎样的数字火花? 最近深度体验了造相Z-Image模型v2在传统艺术风格方面的表现,不得不说,这个模型在模拟水墨、版…...

bge-large-zh-v1.5实测效果:长文本语义匹配精准度展示

bge-large-zh-v1.5实测效果:长文本语义匹配精准度展示 1. 引言 1.1 语义匹配的重要性 在信息爆炸的时代,如何从海量文本中找到语义相关的内容成为关键挑战。无论是构建智能客服系统、开发精准搜索引擎,还是实现文档自动分类,都…...

企业年会春联批量生成方案:Pixel Couplet Gen 结合Java八股文风格创作

企业年会春联批量生成方案:Pixel Couplet Gen 结合Java八股文风格创作 1. 场景痛点:企业年会的文化需求与技术创意 每到年末,行政部门的同事总会面临一个看似简单却令人头疼的任务——为企业年会准备定制化春联。传统方式要么花钱请人创作&…...

BetterGenshinImpact多开终极指南:同时管理多个原神账号的完整教程

BetterGenshinImpact多开终极指南:同时管理多个原神账号的完整教程 【免费下载链接】better-genshin-impact 📦BetterGI 更好的原神 - 自动拾取 | 自动剧情 | 全自动钓鱼(AI) | 全自动七圣召唤 | 自动伐木 | 自动刷本 | 自动采集/挖矿/锄地 | 一条龙 | …...

终极鸣潮自动化指南:如何用OK-WW轻松实现后台自动战斗与声骸刷取

终极鸣潮自动化指南:如何用OK-WW轻松实现后台自动战斗与声骸刷取 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸 一键日常 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 作为《…...

【Nginx】前端项目开启 Gzip 压缩大幅提高页面加载速度

背景 Gzip 是一种文件压缩算法,减少文件大小,节省带宽从而提减少网络传输时间,网站会更快更丝滑。 // nginx roothcss-ecs-1d22:/etc/nginx# nginx -v nginx version: nginx/1.24.0// node ndde v18.20.1// dependencies "vue": &q…...

应对极端姿态与表情:cv_resnet101_face-detection_cvpr22papermogface 鲁棒性极限测试

应对极端姿态与表情:cv_resnet101_face-detection_cvpr22papermogface 鲁棒性极限测试 今天咱们不聊常规操作,来点刺激的。人脸检测模型平时表现都挺好,证件照、生活照基本不在话下。但真到了“实战”环境,情况就复杂多了&#x…...

tao-8k镜像免配置部署教程:开箱即用的Xinference Embedding服务

tao-8k镜像免配置部署教程:开箱即用的Xinference Embedding服务 你是不是也遇到过这样的烦恼:想用个强大的文本嵌入模型,结果光是环境配置、依赖安装、模型下载就折腾了大半天,最后还可能因为版本冲突、路径不对而失败&#xff1…...

新手友好!Qwen3-ASR-0.6B语音识别使用指南:解决90%常见问题

新手友好!Qwen3-ASR-0.6B语音识别使用指南:解决90%常见问题 语音识别技术正在改变我们处理音频内容的方式,但复杂的部署流程和晦涩的技术术语往往让初学者望而却步。Qwen3-ASR-0.6B作为一款轻量级多语言语音识别模型,以其开箱即用…...

实战:若依框架下异步日志管理器的设计与实现

1. 若依框架异步日志管理器的核心价值 在Web应用开发中,日志记录是系统监控和故障排查的重要依据。传统同步日志记录方式会阻塞主线程,导致用户请求响应时间延长。若依框架通过异步日志管理器完美解决了这个问题,我在多个生产项目中实测发现&…...

线程同步与互斥(下)

线程同步与互斥(中)https://blog.csdn.net/Small_entreprene/article/details/147003513?fromshareblogdetail&sharetypeblogdetail&sharerId147003513&sharereferPC&sharesourceSmall_entreprene&sharefromfrom_link我们学习了互斥…...

从原理到实践:深入理解react-native-fetch-blob的底层架构设计

从原理到实践:深入理解react-native-fetch-blob的底层架构设计 【免费下载链接】react-native-fetch-blob A project committed to making file access and data transfer easier, efficient for React Native developers. 项目地址: https://gitcode.com/gh_mirr…...

云容笔谈·东方红颜影像生成系统Python爬虫数据驱动创作实战

云容笔谈东方红颜影像生成系统Python爬虫数据驱动创作实战 最近在尝试用AI绘画工具“云容笔谈”来创作一些古风角色,效果确实惊艳。但有个问题一直困扰我:每次想画一个新角色,都得绞尽脑汁去想外貌、服饰、神态的描述词,效率很低…...

一些算法题的反思总结

1.技巧总结有序———想二分连续———①滑动窗口② DP(dp[i]表示以i结尾的xxxxx)③前缀和,f(ij)-f(i)重复——哈希/Counter/defaultdict子问题——1️⃣递归,先定义结束如何退出,再考虑当前值怎么做2️⃣动态规划&…...

Pixel Aurora Engine 工业设计渲染:生成产品概念图与材质表现

Pixel Aurora Engine 工业设计渲染:生成产品概念图与材质表现 1. 工业设计渲染的新标杆 在工业设计领域,概念图的快速生成和材质表现一直是设计师面临的核心挑战。传统3D建模软件虽然功能强大,但学习曲线陡峭,渲染耗时漫长。而P…...

Linux操作系统进程(下)

Linux操作系统进程(下) 深入理解进程概念,了解PCB学习进程状态,创建进程,掌握僵尸进程和孤儿进程的形成和危害了解进程的调度,Linux进程优先级,理解进程竞争性与独立性 文章目录Linux操作系统进程(下)进程和PCB进程概…...

项目实战:从零构建基于Miniedit与Floodlight的SDN可视化拓扑

1. 为什么需要SDN可视化工具? 刚接触软件定义网络(SDN)时,最让我头疼的就是命令行配置。记得第一次用Mininet创建拓扑,光是记住那些addHost、addSwitch命令就花了半天时间,更别提调试链路参数时频繁出现的报…...

Synopsys综合指令进阶指南:为什么90%的工程师都用错了full_case?

Synopsys综合指令进阶指南:为什么90%的工程师都用错了full_case? 在数字电路设计领域,Synopsys工具链中的full_case指令就像一把双刃剑——用得好可以优化电路结构,用不好则可能导致仿真与综合结果不一致的灾难性后果。本文将带您…...

版本降级实战:在VirtualBox 6.0.24中成功启用嵌套虚拟化

1. 为什么要在旧版本中启用嵌套虚拟化? 最近在调试一个遗留项目时,遇到了一个棘手的问题:客户的生产环境使用的是VirtualBox 6.0.24版本,而我们需要在这个虚拟机里再运行一个虚拟机(也就是嵌套虚拟化)。这个…...

软考 系统架构设计师系列知识点之杂项集萃(117)

接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(116) 第214题 在磁盘上存储数据的排列方式会影响I/O服务的总时间。假设每磁道划分成10个物理块,每块存放1个逻辑记录。逻辑记录R1,R2,……,R10存放在同一个磁道上,记录的安排顺序如下表所示: 物理块 1 2 3 4 5…...

终极指南:Kanboard监控告警配置 - 打造异常情况及时响应机制

终极指南:Kanboard监控告警配置 - 打造异常情况及时响应机制 【免费下载链接】kanboard Kanban project management software 项目地址: https://gitcode.com/gh_mirrors/ka/kanboard Kanboard作为一款高效的看板项目管理软件,不仅能帮助团队可视…...

FFmpeg在RK3588上的完整移植教程:从交叉编译到CMake集成

FFmpeg在RK3588上的完整移植指南:从编译优化到项目实战 在嵌入式多媒体开发领域,RK3588凭借其强大的视频处理能力已成为众多视觉项目的首选平台。而要让这个四核Cortex-A76处理器真正发挥出4K120帧的解码潜力,FFmpeg的深度优化移植是不可或缺…...

MiniCPM-o-4.5-nvidia-FlagOS进阶:使用Matlab进行模型输出数据的可视化分析

MiniCPM-o-4.5-nvidia-FlagOS进阶:使用Matlab进行模型输出数据的可视化分析 最近在折腾MiniCPM-o-4.5-nvidia-FlagOS这个本地大模型,用它处理了不少文本分析任务。模型跑起来挺顺畅,生成的结果也很有料,但看着满屏的文本输出&…...

接雨水——单调栈(python)

思路:利用栈的先进后出,后进先出特性。 使用单调栈,入栈下标。当遇到更高的墙时,说明形成了凹槽,弹出栈元素,开始计算接水量。每次弹出栈后,记得要判空,因为这里用的是大于&#xff…...

光纤收发器指示灯故障排查指南:从状态解析到快速修复

1. 光纤收发器指示灯全解析:你的网络健康晴雨表 刚入行那会儿,我最怕遇到光纤网络故障。直到师傅教我:"看灯!那些小灯泡比网管系统反应还快。"确实,光纤收发器面板上那些彩色指示灯,就像设备的&q…...

什么是电商CRM系统?从入门到精通,全面解析其定义与功能模块

在电商行业竞争日益激烈的今天,如何高效管理客户关系、提升用户价值已成为品牌增长的关键。本文将带您全面了解电商CRM系统,从基础概念到功能模块,再到行业解决方案,助您掌握这一提升业绩的利器。一、电商CRM:数字化时…...

Spring Boot微服务镜像瘦身实战:从600MB到80MB,Dockerfile优化全记录

Spring Boot微服务镜像瘦身实战:从600MB到80MB的Dockerfile优化全记录 在微服务架构中,镜像体积直接影响部署效率和运维成本。一个典型的Spring Boot应用原始镜像往往超过600MB,这不仅浪费存储空间,还会拖慢CI/CD流水线的构建和分…...

告别CUDA!用OpenAI Triton写GPU Kernel,Python开发者也能玩转高性能计算

用Python解锁GPU算力:OpenAI Triton实战指南 当Python遇上GPU计算,传统路径总是绕不开CUDA C的陡峭学习曲线。但现在,OpenAI Triton正在改写这一规则——它让开发者能够用熟悉的Python语法编写高性能GPU内核,像操作NumPy数组一样自…...

OpenClaw+Qwen2.5-VL-7B学术助手:论文图表解析与摘要生成

OpenClawQwen2.5-VL-7B学术助手:论文图表解析与摘要生成 1. 为什么需要AI学术助手 作为一名经常需要阅读大量文献的研究人员,我长期被三个问题困扰:首先是PDF论文中的图表数据提取困难,手动转录既耗时又容易出错;其次…...