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

7.0 android中Service的基础知识

service的定义:

Service 是一个在后台执行长时间运行操作而不提供用户界面的组件。

允许在用户没有与应用交互时操作,或者执行一些用户交互之外的操作,如音乐播放、文件上传、文件下载等。
Service的使用不影响用户的交互,且由其他组件(如Activity、Fragment等)启动

Service必须在Manifest中进行定义。

service的特点:

  • 适合执行不需要和用户交互而且还要求长期运行的任务
  • 依赖于创建Service时所在的应用程序进程
  • 默认运行在主线程当中的,不能直接执行耗时操作,需要开启子线程

Service 直接启动

启动

通过startService启动Service

停止

通过stopService停止Service
在Service中可以通过stopSelf()停止Service。

示例

下列代码示例中,设置两个按钮执行开始Service和结束Service

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)startServiceBtn.setOnClickListener {val intent = Intent(this, MyService::class.java)startService(intent) // 启动Service}stopServiceBtn.setOnClickListener {val intent = Intent(this, MyService::class.java)stopService(intent) // 停止Service}}}

Service 绑定启动

假设执行一个后台下载的功能

定义Service

  • 在service中设置一个继承Binder()的类,并在Service中创建变量mBinder为其实例。

  • 在Service中的方法onBind中返回mBinder,用于Activity与Service之间绑定。

class MyService : Service() {private val mBinder = DownloadBinder()class DownloadBinder : Binder() {fun startDownload() {Log.d("MyService", "startDownload executed")}fun getProgress(): Int {Log.d("MyService", "getProgress executed")return 0}}override fun onBind(intent: Intent): IBinder {return mBinder}...
}

绑定

在Activity中,设置Service中定义的Binder类,并通过匿名类ServiceConnection中的onServiceConnected,设置为绑定运行的Service。

启动

在Activty中通过bindService进行绑定启动Service,

停止

通过unbindService进行解绑停止Service的操作。

class MainActivity : AppCompatActivity() {lateinit var downloadBinder: MyService.DownloadBinderprivate val connection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName, service: IBinder) {downloadBinder = service as MyService.DownloadBinderdownloadBinder.startDownload()downloadBinder.getProgress()}override fun onServiceDisconnected(name: ComponentName) {}}override fun onCreate(savedInstanceState: Bundle?) {...bindServiceBtn.setOnClickListener {val intent = Intent(this, MyService::class.java)bindService(intent, connection, Context.BIND_AUTO_CREATE) // 绑定Service}unbindServiceBtn.setOnClickListener {unbindService(connection) // 解绑Service}}}

注意

虽然每调用一次startService()方法,onStartCommand()就会执行一次,但实际上每个Service只会存在一个实例。所以不管你调用了多少次startService()方法,只需调用一次stopService()或stopSelf()方法,Service就会停止。

在同一个Activity中,如果同时通过startService、bindService启动同一个Service,停止Service的话,需要同时通过unbindService和stopService对Service进行解绑和停止的操作。

生命周期

对于Service的生命周期,
方法onCreate只在第一次创建时调用;

方法onStartCommand在使用startService启动Service都会调用;

方法onBind在使用bindService启动ServiceService都会调用。

也就是说,使用不同的方法启动Service,调用Service的生命周期的方法是不一样的,如果需要在Service每次启动时执行一定操作,要注意方法是否调用正确。

前台service

从Android 8.0系统开始,只有当应用保持在前台可见状态的情况下,Service才能保证稳定运行,一旦应用进入后台之后,Service随时都有可能被系统回收。如果你希望Service能够一直保持运行状态,就可以考虑使用前台Service。

class MyService : Service() {...override fun onCreate() {super.onCreate()Log.d("MyService", "onCreate executed")val manager = getSystemService(Context.NOTIFICATION_SERVICE) asNotificationManagerif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {val channel = NotificationChannel("my_service", "前台Service通知",NotificationManager.IMPORTANCE_DEFAULT)manager.createNotificationChannel(channel)}val intent = Intent(this, MainActivity::class.java)val pi = PendingIntent.getActivity(this, 0, intent, 0)val notification = NotificationCompat.Builder(this, "my_service").setContentTitle("This is content title").setContentText("This is content text").setSmallIcon(R.drawable.small_icon).setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.large_icon)).setContentIntent(pi).build()startForeground(1, notification)}...
}

IntentService

Service中的代码都是默认运行在主线程当中的,如果直接在Service里处理一些耗时的逻辑,就很容易出现ANR(Application Not Responding)的情况。
为了可以简单地创建一个异步的、会自动停止的Service,Android专门提供了一个IntentService类

class MyIntentService : IntentService("MyIntentService") {override fun onHandleIntent(intent: Intent?) {// 打印当前线程的idLog.d("MyIntentService", "Thread id is ${Thread.currentThread().name}")}override fun onDestroy() {super.onDestroy()Log.d("MyIntentService", "onDestroy executed")}}

实际其相对于如下代码:

class MyService : Service() {...override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {thread {// 处理具体的逻辑stopSelf()}return super.onStartCommand(intent, flags, startId)}
}

步骤

①先调用父类的构造函数
②在子类中实现onHandleIntent()这个抽象方法,这个方法中可以处理一些耗时的逻辑,而不用担心ANR的问题,因为这个方法已经是在子线程中运行的了

相关文章:

  • BeagleBone Black入门总结
  • 四种跨域解决方案
  • 初识C++ · 模拟实现list
  • 从零手写实现 nginx-11-文件处理逻辑与 range 范围查询合并
  • 使用Python操作Redis
  • Redis 内存回收
  • Debezium日常分享系列之:Debezium 2.6.2.Final发布
  • Nginx(openresty) 查看连接数和并发送
  • 【SpringCloud学习笔记】Docker(上篇)
  • 提高篇(五):使用Processing创作互动艺术:从灵感到实现
  • QUIC 的多路径扩展
  • 【Vue3】理解toRef() 和 toRefs()
  • ChatGPT-4o体验demo
  • Docker面试整理-如何管理Docker容器的安全?
  • 【python报错】TypeError: dict.get() takes no keyword arguments
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 【翻译】babel对TC39装饰器草案的实现
  • 08.Android之View事件问题
  • Javascript 原型链
  • PHP 小技巧
  • React的组件模式
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • vue:响应原理
  • 给新手的新浪微博 SDK 集成教程【一】
  • 简单数学运算程序(不定期更新)
  • 力扣(LeetCode)22
  • 使用Swoole加速Laravel(正式环境中)
  • 我的zsh配置, 2019最新方案
  • 项目管理碎碎念系列之一:干系人管理
  • 再次简单明了总结flex布局,一看就懂...
  • 自动记录MySQL慢查询快照脚本
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 阿里云服务器如何修改远程端口?
  • ​Redis 实现计数器和限速器的
  • ​学习笔记——动态路由——IS-IS中间系统到中间系统(报文/TLV)​
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • $.ajax中的eval及dataType
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (简单) HDU 2612 Find a way,BFS。
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (十八)Flink CEP 详解
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (一)基于IDEA的JAVA基础1
  • ****Linux下Mysql的安装和配置
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .form文件_一篇文章学会文件上传
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net core 的缓存方案
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .net 设置默认首页
  • .NET开发者必备的11款免费工具