Android学习路线_入门篇(四)四大组件之Service

Android应用开发中核心的四大组件是整体应用的骨架,利用好四大组件才能搭建出一个合理高效的APP。了解了Activity之后,我们再认识一下Service,它是一个独立的组件,译为服务,不需要用户交互,可长时间运行,即便程序销毁也可继续工作。

本文已收录至☞Android学习路线_梳理
上一篇☞Android学习路线_入门篇(三)Acitvity生命周期与启动模式
下一篇☞Android学习路线_入门篇(五)Service的生命周期与如何保活

1. 创建一个Service

和Activity类似,要使用一个Service首先需要在清单文件中注册,然后创建一个Service类,但是它不需要布局文件。

1.1 注册Service

AndroidManifest中添加Service的注册代码,相对Activity的注册来说,Service的注册可就简单多了,只需要在application中增加一行代码:

<service android:name=".MyService" />

当然Service也是可以加上<intent-filter></intent-filter>标签的,用法和Activity一致:

<service android:name=".MyService" >
    <intent-filter>
        <action android:name="com.example.MyService.DO_SOMETHING" />
    </intent-filter>
</service>

通过Intent设置对应的action可以进行隐式启动,不过在Android5.0以后有一个Service Intent must be explitict的特性,也就是说从Lollipop开始,service服务必须采用显示方式启动。但是并不是不能避开的,隐式启动还是有些用处的,可不能说没了就没了。我们来看看关键的源码:

private void validateServiceIntent(Intent service) {  
    if (service.getComponent() == null && service.getPackage() == null) {  
        if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {  
            IllegalArgumentException ex = new IllegalArgumentException(  
                    "Service Intent must be explicit: " + service);  
            throw ex;  
        } else {  
            Log.w(TAG, "Implicit intents with startService are not safe: " + service  
                    + " " + Debug.getCallers(2, 3));  
        }  
    }  
}  

可以看到源码中判断的条件是service.getComponent() == null && service.getPackage() == null,那么就有两种办法避开这个判断啦:

  1. 设置Action和packageName:
    此方式是google官方推荐使用的解决方法。参考代码如下:
val mIntent = Intent()
// 设置注册时配置好的action
mIntent.action = "com.example.MyService.DO_SOMETHING"
// 设置当前应用的包名
mIntent.setPackage(getPackageName())
context.startService(mIntent)
  1. 设置ComponentName:
    此方式是其实也类似方法1。参考代码如下:
val mIntent = Intent()
val componentName = ComponentName(pkgName, serviceName)
intent.component = componentName
context.startService(intent) 

1.2 创建类文件

注册完会有有报错提醒,和之前创建Activity是一样的。这里插一句话,之前创建Activity我们的顺序是注册->创建类->创建布局,每做一步都会有报错提醒,直到最后完成才恢复正常。

有小伙伴就有疑问了,如果反过来的话就完全没有报错,这里有什么玄机吗?

首先报错的原因是注册是用了类但是类没创建,类创建时用了布局但是布局没创建,反过来就没有这种依赖关系。其次有报错的情况下,就逼着我们要去解决,对于初学者来说有一个好处,那就是提醒你还有文件没创建,防止漏了步骤最后程序跑起来遇到崩溃或者没反应的问题。

那么下一步就是创建类文件了,我们还是在src/main/java/com/example/myapplication/路径新建一个类MyService,因为我们在注册时用的是.MyService

package com.example.myapplication

import android.app.Service
import android.content.Intent
import android.os.IBinder

class MyService: Service() {
    override fun onBind(intent: Intent?): IBinder? {
	    return null
    }
}

创建很简单,必须实现的方法只有onBind(),而且可以直接返回null。这时候的MyService不能做任何事,想要起作用就需要我们重写父类的onStartCommand()方法,最好再重写onDestroy()方法:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    Toast.makeText(this, "服务启动", Toast.LENGTH_SHORT).show()
    return super.onStartCommand(intent, flags, startId)
}

override fun onDestroy() {
    super.onDestroy()
    Toast.makeText(this, "服务停止", Toast.LENGTH_SHORT).show()
}

这里实现了两个简单操作,Toast是一个简单的提示控件,通常是在屏幕底部弹出一个浮动文本框。

2. 启动Service

使用一个Service需要通过其他组件启动Service,随后才会触发onStartCommand()方法执行Service的业务逻辑。而Service的启动方法有两种:startService()bindService(),这两种模式下生命周期有所不同,运行的机制也有区别。

2.1 startService方式

startService方式启动需要写的代码特别少,只需要在你想要启动它的地方加上一小段代码。我们来重写MainActivity的onStart()方法,加入这段代码:

override fun onStart() {
    super.onStart()
    val intent = Intent(this, MyService::class.java)
    startService(intent)
}

这时候MyService就启动了,运行起来自动打开MainActivity,你可以看到屏幕底部弹出服务启动的提示语。但是这时候不论你如何操作都无法看到服务停止的提示语。

Android的应用程序组件,如活动(Activity),通过startService()启动了服务,则服务是Started状态。一旦启动,服务可以在后台无限期运行,即使启动它的组件已经被销毁。

那么我们如何停止一个服务呢?和startService启动服务类似,在你想要关闭它的地方加上stopService的逻辑,比如在MainActivity中重写onStop()方法,加入这段代码:

override fun onStop() {
    super.onStop()
    val intent = Intent(this, MyService::class.java)
    stopService(intent)
}

重新运行项目,自动打开MainActivity,你可以看到屏幕底部弹出服务启动的提示语。这时候点击物理返回键或者桌面键,你可以看到屏幕底部弹出服务停止的提示语。

2.2 bindService方式

bindService的方式需要提供一个ServiceConnection对象,我们来改写之前的启动逻辑:

private var sc: MyServiceConnection? = null

override fun onStart() {
    super.onStart()
    sc = MyServiceConnection()
    val intent = Intent(this, MyService::class.java)
    bindService(intent, sc, Context.BIND_AUTO_CREATE)
}

override fun onStop() {
    super.onStop()
    unbindService(sc)
}

class MyServiceConnection: ServiceConnection {
    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        // service: IBinder? 就是MyService里onBind()方法的返回值
    }
    override fun onServiceDisconnected(name: ComponentName?) {
    }
}

当Android的应用程序组件通过bindService()绑定了服务,则服务是Bound状态。Bound状态的服务提供了一个客户服务器接口来允许组件与服务进行交互,如发送请求,获取结果,甚至通过IPC来进行跨进程通信。

完毕

今天的分享就到这里,文章多有不足,各位小伙伴有什么想法可以直接评论或是私信,要是对你有所帮助就给我一个赞吧,喜欢我的小伙伴可以关注我哦~

本文已收录至☞Android学习路线_梳理
上一篇☞Android学习路线_入门篇(三)Acitvity生命周期与启动模式
下一篇☞Android学习路线_入门篇(五)Service的生命周期与如何保活

支持我的小伙伴们可以微信搜索“Android思维库”,或者微信扫描下方二维码,关注我的公众号,每天都会推送新知识~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值