Service 的两种启动方式和「Service 与 Activity 数据交互」
1. Service 的两种启动方式
Activity 中可以有两种方式启动 Service,不同方式启动时 Service 的生命周期也不一样,现在在 Activity 中定义四个 Button,分别是 startService
、stopService
、bindService
、unbindService
,Service 中各生命周期中分别打印 Log 日志,通过日志查看生命周期执行情况:
// MainActivity.kt class MainActivity : AppCompatActivity(){ var mService: MyService? = null var isBind = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val intent = Intent(this, MyService::class.java) val conn = object : ServiceConnection { override fun onServiceDisconnected(name: ComponentName?) { Log.e("abc", "-- Activity 中 onServiceDisconnected --") } override fun onServiceConnected(name: ComponentName?, service: IBinder?) { mService = (service as MyService.MyBinder).getService() Log.e("abc", "-- Activity 中 onServiceConnected --") } } startService.setOnClickListener { startService(intent) } stopService.setOnClickListener { stopService(intent) } bindService.setOnClickListener { isBind = bindService(intent, conn, Context.BIND_AUTO_CREATE) } unBindService.setOnClickListener { if (isBind) { isBind = false unbindService(conn) } } } }
// MyService.kt class MyService: Service() { override fun onBind(intent: Intent?): IBinder? { Log.e("abc", "-- onBind --") return MyBinder() } override fun onCreate() { super.onCreate() Log.e("abc", "-- onCreate --") } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.e("abc", "-- onStartCommand --") return super.onStartCommand(intent, flags, startId) } override fun onDestroy() { super.onDestroy() Log.e("abc", "-- onDestroy --") } override fun onUnbind(intent: Intent?): Boolean { Log.e("abc", "-- onUnbind --") return super.onUnbind(intent) } inner class MyBinder : Binder() { fun getService(): MyService { return this@MyService } } }
其实以前 Service 还有个生命周期叫
onStart()
,后来被弃用了,它的功能由onStartCommand()
代替。
1.1 startService
在 MainActivity 中可以这样启动和停止 Service:
// 启动 val intent = Intent(this, MyService::class.java) startService(intent) // 停止 stopService(intent) // Log -- onCreate -- -- onStartCommand -- -- onDestroy --
1.2 bindService
bindService 方式稍微复杂些:
// 绑定 val conn = object : ServiceConnection { override fun onServiceDisconnected(name: ComponentName?) {} override fun onServiceConnected(name: ComponentName?, service: IBinder?) { } } bindService(intent, conn, Context.BIND_AUTO_CREATE) // 停止 unbindService(conn) // Log -- onCreate -- -- onBind -- -- onUnbind -- -- onDestroy --
绑定时会执行 onBind
生命周期,解绑时先调用 onUnbind
再调用onDestroy
。
1.3 两种方式混合
如果先用 startService 方式启动了 Service,再用 bindService 绑定一次(两者顺序也可以颠倒),那么此时单纯的 stopService 或者 unbindService 是无法终止 Service 的,需要二者联合使用才行。具体细化:
1.3.1 先 stopService 后unbindService
// Log -- onCreate -- -- onStartCommand -- -- onBind -- // stopService 无反应 // unbindService: -- onUnbind -- -- onDestroy --
调用 stopService 没有反应,调用 unbindService 时方可销毁 Service。
1.3.2 先 unbindService 后 stopService
-- onCreate -- -- onStartCommand -- -- onBind -- // unbindService -- onUnbind -- // stopService -- onDestroy --
调用 unbindService 只能解绑(onUnbind)不能销毁,调用 stopService 时才可以销毁 Service
1.4 注意事项
- 多次调用 startService 时,Service 中的
onStartCommand
方法会执行多次;但多次使用 bindService 时,onBind
只执行一次。 - bindService 方式打开 Service 时,Service 的生命周期是和打开它的 Activity 绑定的,而 startService 方式打开的 Service 在 Activity 被销毁后(onDestroy),还可以继续存活(可以同时打印 Activity 和 Service 的生命周期查看,这里不举例子了)。
2. Service 与 Activity 数据交互
其实从前面的代码中也可以看出,在 MainActivity 中,可以获取到 Service 的引用(具体来说是onServiceConnected
中),Service 调用 Activity 中的方法主要讲讲。
2.1 Activity 调用 Service 方法
回看 Service 的onBind
生命周期可以发现,该方法返回的是一个 IBinder 类型,我们在具体实现是返回的是它子类的子类(IBinder 的 子类是 Binder,Binder 的子类是 MyBinder),这是一种多态(不懂多态的自己查一下蛤,这篇文章不是介绍多态的,展开说太长了):
// MyBinder 是 Service 我自己定义的里面的内部类 inner class MyBinder : Binder() { fun getService(): MyService { return this@MyService } } // Binder 源码 public class Binder implements IBinder { ...代码省略 } // onBind 生命周期 override fun onBind(intent: Intent?): IBinder? { return MyBinder() } // bindService 方式打开 Service 时用到的 conn val conn = object : ServiceConnection { override fun onServiceDisconnected(name: ComponentName?) { } override fun onServiceConnected(name: ComponentName?, service: IBinder?) { mService = (service as MyService.MyBinder).getService() } }
现在,可以用 mService 对象调用 Service 中的任何方法,比如 printTxt
fun printTxt(txt : String) { Log.e("abc", "-- this is txt -- $txt") }
其实我觉得还可以直接 new 一个 MyService 对象 mService2,然后
myService2.printTxt("装逼")
,好像也没啥区别。
2.2 Service 主动向 Activity 传输数据
Service 没有 Activity 的引用,所以可以通过接口回调或者广播的方式向 Activity 传递数据。
2.2.1 接口回调
定义接口:
interface CallBack { fun call(index: Int) }
Service 中初始化:
private var callBack:CallBack ?= null fun setListener(callBack: CallBack){ this.callBack = callBack }
Activity 实现 CallBack(或者用 匿名内部类):
class MainActivity : AppCompatActivity(), CallBack { override fun call(index: Int) { Log.e("abc", "This is index value : $index") } } mService.setListener(this@MainActivity) // 或者 mService!!.setListener(object :CallBack{ override fun call(index: Int) { Log.e("abc", "This is index value : $index") } })
Service 中有了 callBack 对象,就可以主动向 Activity 传输数据了。
2.2.2 广播
用 Android 自带的 BroadcastReceiver 或者 EventBus 这种第三方框架区别不大,先在 Activity 中注册接受者,然后在 Service 中发射广播数据,不具体举例了。需要说明的是,如果是一个 Service 向多个 Activity 传递数据,广播比回调要好一些。
源码地址
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
一个奇怪的MySQL慢查询,打懵了一群不懂业务的DBA!
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 前言 最近,开发人员需要定期的删除表里一定时间以前的数据,SQL如下: mysql > delete from testtable WHERE biz_date <= '2017-08-21 00:00:00' AND status = 2 limit 500\G 前段时间在优化的时候,我们已经在相应的查询条件上加上了索引,如下: KEY `idx_bizdate_st` (`biz_date`,`status`) 但是实际执行的SQL依然非常慢,为什么呢,我们来一步步分析验证下。 分析 表上的字段既然都有索引,那么按照之前的文章分析,是两个字段都可以走上索引的。 既然能够利用索引,表的总大小也就是200M左右,那么为什么形成了慢查呢? 我们查看执行计划,去掉limit 后,发现他选择了走全表扫描。 mysql > desc select * from testtable WHERE biz_date <= '2017-08-21 00:00:00'; +----...
- 下一篇
puppeteer搭建代理转发请求
使用方法 tnpm install -g @ali/tuzki tuzki set -a 你的账号 tuzki set -p 你的密码 tuzki start tuzki set -a --account ,设置域账号-p --passowrd ,设置域账号密码 tuzki config 输出当前配置的域账号和密码 tuzki start 运行代理,默认是 5000 端口,如果你在 start 后指定了一个端口则会在指定端口运行 tuzki start -p 9000 // 在9000端口运行 开发过程 koa Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。当然,这段话是我抄的。https://koa.bootcss.com/ puppeteer Puppeteer是一个Node库,它提供了高级AP...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS关闭SELinux安全模块
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 设置Eclipse缩进为4个空格,增强代码规范
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路