Android Service学习笔记

1、Service介绍

Android Service(服务)是 Android 四大组件之一,主要作用是执行后台操作。它是一个后台运行的组件,执行长时间运行且不需要用户交互的任务。即使应用被销毁也依然可以工作。
Service并不是运行在一个独立的进程当中的,而是依赖于创建Service时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的Service也会停止运行。
服务基本上包含两种状态:

  • Started:当 Android 的应用程序组件,如活动,通过 startService() 启动了服务,则服务是 Started 状态。一旦启动,服务可以在后台无限期运行,即使启动它的组件已经被销毁。
  • Bound:当 Android 的应用程序组件通过 bindService() 绑定了服务,则服务是 Bound 状态。Bound 状态的服务提供了一个客户服务器接口来允许组件与服务进行交互,如发送请求,获取结果,甚至通过 IPC 来进行跨进程通信。

服务拥有生命周期方法,可以实现监控服务状态的变化,可以在合适的阶段执行工作。例如,onStartCommand() 方法会在其他组件(如活动)通过调用 startService() 来请求启动服务时被系统调用。

要创建服务,你需要创建一个继承自 Service 基类或者它的已知子类的 Java 类。例如,下面是一个简单的 Service 类的示例:

public class MyService extends Service {@Overridepublic void onCreate() {// 服务被创建时调用}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 其他组件通过调用 startService() 来请求启动服务时,系统调用该方法return super.onStartCommand(intent, flags, startId);}@Nullable@Overridepublic IBinder onBind(Intent intent) {// 当其他组件想要通过 bindService() 来绑定服务时,系统调用该方法return null;}@Overridepublic boolean onUnbind(Intent intent) {// 当客户中断所有服务发布的特殊接口时,系统调用该方法return super.onUnbind(intent);}@Overridepublic void onDestroy() {// 当服务不再有用或者被销毁时,系统调用该方法}
}

与之对应的Kotlin代码如下:

class MyService : Service() {// 当其他组件通过bindService来绑定服务时被调用override fun onBind(intent: Intent): IBinder {// 返回一个IBinder对象TODO()}// 在Service被创建时调用override fun onCreate() {super.onCreate()}// 当其他组件通过startService来请求启动Service时,该方法被调用override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {return super.onStartCommand(intent, flags, startId)}// 当服务不再有用或者被销毁时,系统调用该方法override fun onDestroy() {super.onDestroy()}// 当客户中断所有服务发布的特殊接口时,系统调用该方法override fun onUnbind(intent: Intent?): Boolean {return super.onUnbind(intent)}
}

onCreate()方法是在Service第一次创建的时候调用的,而onStartCommand()方法则在每次启动Service的时候都会调用。

2、异步消息处理机制

Android的异步消息处理主要由以下四个部分组成:Message、Handler、MessageQueue和Looper。

  1. Message:Message是在线程之间传递的消息,它可以携带少量的信息,用于在不同线程之间传递数据。我们可以使用Message的whatarg1arg2字段来携带整型数据,或者使用obj字段来携带一个Object对象。

  2. Handler:Handler主要用于发送和处理消息。我们可以使用Handler的sendMessage()post()等方法来发送消息,发送出的消息会最终传递到Handler的handleMessage()方法中进行处理。

  3. MessageQueue:MessageQueue是消息队列,主要用于存放所有通过Handler发送的消息。这些消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。

  4. Looper:Looper是每个线程中的MessageQueue的管家,当调用Looper的loop()方法后,就会进入一个无限循环中。每当发现MessageQueue中存在一条消息时,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中只会有一个Looper对象。

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

class MainActivity : AppCompatActivity() {private val updateText = 1 // 用于标识哪个动作private lateinit var textView: TextView// Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般//是使用Handler的sendMessage()方法、post()方法等,而发出的消息经过一系列地辗//转处理后,最终会传递到Handler的handleMessage()方法中private val handler = object : Handler(Looper.getMainLooper()){override fun handleMessage(msg: Message) {// 在主线程中进行UI操作when(msg.what){updateText -> textView.text = msg.obj.toString()}}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)textView = findViewById<TextView>(R.id.textView)val changeTextBtn = findViewById<Button>(R.id.changeTextBtn)changeTextBtn.setOnClickListener{// 开启一个新的线程thread {// Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间传递数据val message = Message()message.what = updateTextmessage.arg1 = 1 // 携带整型数据message.arg2 = 2message.obj = "你好啊" // 携带对象类型数据// 发送Message对象handler.sendMessage(message)// 通过post方法发送一个 Runnable 对象,这个 Runnable 对象会被添加到消息队列的尾部handler.post(Runnable { Log.d("Handler", "post") })}}}
}
3、Service的使用

例如一个后台下载服务的简单实现

class MyService : Service() {private val mBinder = DownloadBinder()// 当其他组件通过bindService来绑定服务时被调用override fun onBind(intent: Intent): IBinder {// 返回一个IBinder对象return mBinder}// 在Service被创建时调用override fun onCreate() {super.onCreate()}// 当其他组件通过startService来请求启动Service时,该方法被调用override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {return super.onStartCommand(intent, flags, startId)}// 当服务不再有用或者被销毁时,系统调用该方法override fun onDestroy() {super.onDestroy()}// 当客户中断所有服务发布的特殊接口时,系统调用该方法override fun onUnbind(intent: Intent?): Boolean {return super.onUnbind(intent)}class DownloadBinder : Binder() {fun startDownload() {Log.d("MyService", "startDownload executed")}fun getProgress(): Int {Log.d("MyService", "getProgress executed")return 0}}
}
class MainActivity2: AppCompatActivity(){private lateinit var mBinder: MyService.DownloadBinder// ServiceConnection用于监听服务的状态, 以便于在服务绑定成功时执行相应的逻辑private val connection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {mBinder = service as MyService.DownloadBindermBinder.startDownload()mBinder.getProgress()}override fun onServiceDisconnected(name: ComponentName?) {}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 启动服务findViewById<Button>(R.id.startServiceBtn).setOnClickListener {val intent = Intent(this, MyService::class.java)startService(intent)}// 停止服务findViewById<Button>(R.id.stopServiceBtn).setOnClickListener {val intent = Intent(this, MyService::class.java)stopService(intent)}// 绑定服务,这样Activity和Service就建立了关联findViewById<Button>(R.id.bindServiceBtn).setOnClickListener {val intent = Intent(this, MyService::class.java)// 传入参数:intent, ServiceConnection, flags,// flags一般传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建ServicebindService(intent, connection, BIND_AUTO_CREATE)}// 解绑服务findViewById<Button>(R.id.unbindServiceBtn).setOnClickListener {unbindService(connection)}}
}
4、前台Service

从Android 8.0系统开始,只有当应用保持在前台可见状态的情况下,Service
才能保证稳定运行,一旦应用进入后台之后,Service随时都有可能被系统回收。而如果你希望Service能够一直保持运行状态,就可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,它一直会有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。

class FrontService : Service(){override fun onCreate() {super.onCreate()val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManagerval channel = NotificationChannel("my_service","前台Service通知",NotificationManager.IMPORTANCE_DEFAULT)manager.createNotificationChannel(channel)val intent = Intent(this, MainActivity::class.java)val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)val notification = NotificationCompat.Builder(this, "my_service").setContentTitle("Content title").setContentText("content text").setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher_round)).setContentIntent(pendingIntent).build()// 第一个参数是通知的id,类似于notify()方法的第一个参数;第二个参数则是//构建的Notification对象。调用startForeground()方法后就会让MyService变成一个前//台Service,并在系统状态栏显示出来。startForeground(1, notification)}override fun onBind(intent: Intent?): IBinder? {TODO("Not yet implemented")}}

这里需要声明权限,同时指定Service的foregroundServiceType(根据实际选择)

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<service android:name=".FrontService"android:enabled="true"android:exported="true"android:foregroundServiceType="mediaPlayback"/>
4、IntentService

Service中的代码都是默认运行在主线程当中的,如果直接在Service里处理一些耗时的逻辑,就很容易出现ANR(Application Not Responding)的情况。
应该在其他线程处理耗时操作,如下所示。

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {thread {// 开启一个线程执行耗时操作stopSelf() // 操作执行完毕关闭Service}return super.onStartCommand(intent, flags, startId)}

Android提供了IntentService,这种Service在执行完后自动销毁。

class MyIntentService: IntentService("MyIntentService"){// 新增了一个方法,该方法已经在子线程中执行,所以将耗时操作放在这里override fun onHandleIntent(intent: Intent?) {TODO("Not yet implemented")}// 其他方法和普通Service一样override fun onCreate() {super.onCreate()}
}

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

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

相关文章

【送模板】5张图,帮你轻松搞懂OKR工作法

OKR是目标与关键结果法的缩写&#xff0c;OKR运用在工作中就是强调对业务进行逻辑思考&#xff0c;找到目标与关键结果之间的因果关系。这种因果关系的是否准确决定我们努力的价值。 OKR是一种高效的目标管理方法。“O”就是object&#xff0c;目标的意思&#xff0c;“kr”就…

81600B keysight 是德 可调谐激光源 简述

KEYSIGHT 81600B 是可调谐激光源模块&#xff0c;广泛应用于光通信和光学测试领域。该系列产品通过低自发源发射&#xff08;low SSE&#xff09;技术实现了高信噪比&#xff08;>70 dB/nm&#xff09;&#xff0c;并具有快速准确的扫描能力&#xff0c;覆盖1260 nm至1640 n…

2024 年 Python 基于 Kimi 智能助手 Moonshot Ai 模型搭建微信机器人(更新中)

注册 Kimi 开放平台 Kimi&#xff1a;https://www.moonshot.cn/ Kimi智能助手是北京月之暗面科技有限公司&#xff08;Moonshot AI&#xff09;于2023年10月9日推出的一款人工智能助手&#xff0c;主要为用户提供高效、便捷的信息服务。它具备多项强大功能&#xff0c;包括多…

大模型 舆情分析 数据构造 prompt提示词 经验分享 数据准备

最近在做舆情分析&#xff0c;需要执行比较复杂的任务流程&#xff08;例如同时执行人名识别、相关机构识别、90分类&#xff09;&#xff0c;传统Bert无法胜任&#xff0c;因此尝试使用大模型进行处理。 下面的一些提示词是我用来准备数据的&#xff0c;这些数据可以按照不同…

flutter 导出iOS问题3

更新flutter版本后 macminihaomacMiniaodeMini SocialIM % flutter --version Flutter 3.7.12 • channel stable • https://github.com/flutter/flutter.git Framework • revision 4d9e56e694 (1 year, 2 months ago) • 2023-04-17 21:47:46 -0400 Engine • revision 1a6…

MDPO:Conditional Preference Optimization for Multimodal Large Language Models

MDPO: Conditional Preference Optimization for Multimodal Large Language Models 相关链接&#xff1a;arxiv 关键字&#xff1a;多模态、大型语言模型、偏好优化、条件偏好优化、幻觉减少 摘要 直接偏好优化&#xff08;DPO&#xff09;已被证明是大型语言模型&#xff08…

什么是“基准测试集”呢?

基准测试集有三部分构成&#xff1a;DocumentSet、QuerySet、RelevantJudgement。在比较多个IR系统孰优孰劣的时候&#xff0c;要做的就是&#xff1a;使用统一的DecumentSet建立索引&#xff0c;然后使用统一的QuerySet去进行查询&#xff0c;最后使用统一的judgement进行评判…

OpenAI新模型发布,免费开放GPT-4o!但只开放一点点...

GPT-4o 中的“o”代表“omni”——指的是 GPT-4o 的多模态。 该模型将向免费客户开放&#xff0c;这意味着任何人都可以通过 ChatGPT 访问 OpenAI 最先进的技术。 GPT-4o 是 OpenAI 昨天晚上发布的新旗舰模型&#xff0c;可以实时推理音频、视觉和文本。 据官方介绍&#xff0…

编写C语言程序解决多个数学问题及修正斐波那契数列递归函数

目录 请按下列要求编写程序&#xff1a;(三个函数均在一个C语言源程序) 有一个四位整数&#xff0c;它的9倍恰好是其反序数&#xff08;反序数例&#xff1a;1234与4321互为反序数&#xff09;。 有3个非零十进制数字&#xff0c;用它们可以组合出6个不同的三位数&#xff0…

通过阿里云OOS定时升级Redis实例临时带宽

功能背景 在数据驱动的现代业务环境中&#xff0c;Redis以其卓越的性能和灵活性&#xff0c;已成为众多企业关键基础设施的重要组成部分。Redis广泛应用于处理缓存、会话管理、消息队列等多种数据密集型和响应敏感型的场景&#xff0c;对业务连续性和用户体验贡献极大。然而&a…

如何用Vue3构建一个交互式树状图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 Vue 3 ApexCharts Treemap 组件&#xff1a;可视化多维数据 应用场景 树形图&#xff08;Treemap&#xff09;是一种可视化多维数据的有效方式&#xff0c;特别适用于展示层次结构数据或按类别分组的数据。它…

AI工具对音乐的不良影响

AI工具对音乐的不良影响主要体现在以下几个方面&#xff1a; 一、加剧音乐行业的竞争 门槛降低&#xff1a;由于AI工具可以更容易地生成音乐作品&#xff0c;这降低了音乐制作的门槛&#xff0c;使得更多的人能够参与到音乐创作中来。这虽然增加了音乐创作的多样性&#xff0…

Webmin在EPICS IOC启动中的应用

本文使用webmin启动远程工控机中的EPICS IOC&#xff0c;受控设备使用PI公司的六轴台以及相应的控制器C-887&#xff1a; 1&#xff09;控制器C-887 2) 六轴台&#xff1a; 3&#xff09;在工控机上安装用于与C-887控制器进行通信的EPICS IOC程序&#xff0c;安装结束后&#…

【DBA早下班系列】—— 并行SQL/慢SQL 问题该如何高效收集诊断信息

1. 前言 OceanBase论坛问答区或者提交工单支持的时候大部分时间都浪费在了诊断信息的获取交互上&#xff0c;今天我就其中大家比较头疼的SQL问题&#xff0c;给大家讲解一下如何一键收集并行SQL/慢SQL所需要的诊断信息&#xff0c;减少沟通成本&#xff0c;让大家早下班。 2. …

【杂记-浅谈OSPF协议中的RouterDeadInterval】

一、RouterDeadInterval概述 RouterDeadInterval&#xff0c;即路由器死区间隔&#xff0c;它涉及到路由器如何在广播网络上发现和维护邻居关系。RouterDeadInterval指的是在广播网络中&#xff0c;路由器在多长时间内没有收到邻居路由器的Hello报文后&#xff0c;会将邻居路由…

Python网络爬虫4-实战爬取pdf

1.需求背景 爬取松产品中心网站下的家电说明书。这里以冰箱为例&#xff1a;松下电器-冰箱网址 网站分析&#xff1a; 第一步&#xff1a; 点击一个具体的冰箱型号&#xff0c;点击了解更多&#xff0c;会打开此型号电器的详情页面。 第二步&#xff1a;在新打开的详情页面中…

小抄 20240612

1 很多问题都有人经历过&#xff0c;都交出过自己的答卷&#xff0c;遇到自己无法解决的问题的时候&#xff0c;可以找找别人给出过的参考答案。 2 和人发生矛盾&#xff0c;尽量就事论事&#xff0c;把道理和逻辑说透&#xff0c;关系还在。 千万不要靠情绪解决问题&#x…

docker安装使用

文章目录 docker产生的原因传统虚拟机容器化技术 docker组成安装docker镜像加速docker安装过程中遇到的问题以及解决办法Errors during downloading metadata for repository root_:Failed to set locale, defaulting to C.UTF-8 docker产生的原因 传统虚拟机 在不使用docker…

图纸管理的方法、图纸管理软件

图纸管理是一个复杂且关键的过程&#xff0c;它涉及到图纸的创建、存储、共享、修改、审核、存档和检索等多个环节。以下是根据参考文章总结的图纸管理的具体内容和方法&#xff1a; 一、图纸管理的目的 1、确保图纸的准确性&#xff1a;通过规范的管理流程和质量控制措施&…

bms中BAT+ BAT- PACK+ pack-分别代表什么意思

在电子设备和电池管理系统&#xff08;BMS&#xff09;中&#xff0c;BAT、BAT-、PACK 和 PACK- 是常见的术语&#xff0c;它们代表与电池连接相关的不同电气节点或引脚。下面是这些术语的具体含义&#xff1a; BAT (Battery Positive): BAT 代表电池的正极连接点。在电池组或单…