博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android-认识Service
阅读量:6318 次
发布时间:2019-06-22

本文共 6950 字,大约阅读时间需要 23 分钟。

Android-认识Service

学习自

What is Service

A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding declaration in its package's AndroidManifest.xml. Services can be started with and .

Service 是一个应用程序组件,其代表着一个应用程序希望在不与用户交互的情况下执行一个长时间运行的操作或者为其他的应用程序提供功能。每一个Service都必须在Manifest.xml文件中有一个与之相对应的 <serivce> 标签。Service能有以 Context.startServiceContext.bindService 的方式启动。

Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work.

请注意服务像其他的应用程序对象一样,运行在其托管进程的主线程中。这意味着,如果你的服务打算做任何CPU密集型任务(比如播放MP3)或者堵塞线程的操作(比如链接网络).那么它应该生成自己的线程来做这些工作。

理解官方文档

从官方文档我们了解到,服务是一个运行与后台的并且是运行在主线程中的应用程序组件,服务经常会被用来做一些长时间运行的操作,但是如果是CPU密集型的操作或者网络请求操作的话,需要再开启线程来完成这些操作。

我们可以通过 startServicebindService 两种方式来开启服务。

服务的基本用法

首先呢,我们先来新建一个服务并启动它,与Activity相同,同样是通过Intent来启动服务。

Step 1 新建一个类来继承Service

class TestService : Service() {    override fun onBind(intent: Intent?): IBinder {        TODO("not implemented")    }    override fun onCreate() {        super.onCreate()        "onCreate".logE()    }    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {        "onStartCommand".logE()        return super.onStartCommand(intent, flags, startId)    }    override fun onDestroy() {        super.onDestroy()        "onDestroy".logE()    }}

Step2 在Manifest文件中声明

Step3: 开启服务

界面布局文件

Activity

//开启服务fun startService(view: View) {    val testServiceIntent = Intent(this, TestService::class.java)    this.startService(testServiceIntent)}//关闭服务fun stopService(view: View) {    val stopTestServiceIntent = Intent(this, TestService::class.java)    this.stopService(stopTestServiceIntent)}

Step 4 运行程序查看Log

当点击Start Service按钮的时候Log如下:

onCreateonStartCommand

但是当我们在点击一次StartService按钮的时候,Log如下

onStartCommand

这是因为当我们在点击第一次Start Service的时候因为Service还有创建,这时候需要先创建服务,所以执行了 onCreate 声明周期方法,然后紧接着这时候Service已经创建完成开始运行,执行了 onStartCommand 声明周期方法,当我们第二次点击Start Service按钮的时候,因为此时刚刚创建的Service并没有被销毁,所以仅仅执行了 onStartCommand 方法,onStartCommand 可以多次执行,但是onCreate方法只会在创建Service的时候执行。

当我们点击 Stop Service的时候然后再点击Start Service的时候Log如下:

onDestroyonCreateonStartCommand

当点击 Stop Service 服务会被销毁,然后如果我们再次点击 Start Service 的时候,因为服务已经被销毁所以,服务重新被创建,onCreate方法再次执行,这正好印证了我们上面的说法。

Start方式开启Service的生命周期

开启Service有两种方式,一种是startService,一种是bindService,上面例子中开启服务是通过startService的方式,start的方式开启服务与bind方式开启的Service的声明周期不太相同,我们先来看一下start方式的生命周期。

image.png | left | 424x580

上图就是startService的方式开启的服务的声明周期,当服务创建以后如果不是内存不足服务被系统杀死,或者客户端停止服务,那么服务将会一直存在,尽管没有执行任何的业务。

bindService-Service与Activity通信

在上面我们学习了,通过start的方式启动Activity,但是start方式开启服务的Activity与Service之间的联系实在是太过于松散了,Activity不能够对服务进行有效的控制,可不能获取服务的实时状态,start方式仅仅能够控制服务的开启和技术,然而更具体地控制服务的话就没有办法了,那么有没有其他的办法呢?有的!那就是通过bind的方式开启Service。

我们继续基于我们的TestService来修改,在TestService中一直有一个 onBind 方法我们没有用到,这个方法就是用来与Activity建立联系的方法。

Step 1 修改原来的TestService

class TestService : Service() {    private val mTestBinder = TestBinder()    /**     * 返回Binder     * */    override fun onBind(intent: Intent?): IBinder {        return mTestBinder    }    override fun onCreate() {        super.onCreate()        "onCreate".logE()    }    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {        "onStartCommand".logE()        return super.onStartCommand(intent, flags, startId)    }    override fun onDestroy() {        super.onDestroy()        "onDestroy".logE()    }    //建立我们的Binder类    inner class TestBinder : Binder() {        fun startDownload() = "Downloading".logE()    }}

在上面的代码中,建立了一个继承自Binder的内部类,并在在 onBind 方法执行的时候,将TestBinder的实例返回了出去,在Activity中将会通过这个类来与Service交互。这里仅仅是模拟一下,所以只打了个Log。

Step 2 向布局文件中在添加几个Button,用来与服务交互

Step 3 调用Service

class MainActivity : AppCompatActivity() {    private var mBinder: TestService.TestBinder? = null    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)    }    //....OLD CODE        //绑定服务    fun bindingService(view: View) {        var bindingIntent = Intent(this, TestService::class.java)        this.bindService(bindingIntent, serviceConnection, android.app.Service.BIND_AUTO_CREATE)    }    //解绑服务    fun unbindingService(view: View) {        this.mBinder = null        this.unbindService(serviceConnection)    }    //通过Binder与Service交互    fun downloadFile(view: View) {        mBinder?.startDownload() ?: "mBinder has been released".logE()    }    /**     * ServiceConnection 是一个用来监测Service状态的接口     * 当与Service建立联系后,会调用相应的方法来通知Activity     * */    private val serviceConnection = object : ServiceConnection {        override fun onServiceDisconnected(name: ComponentName?) {        }        //在与Service建立链接后会执行此方法,在此方法中我们可以获取到对应服务的Binder        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {            this@MainActivity.mBinder = service as TestService.TestBinder            "链接建立".logE()        }    }}

Step4 运行程序查看Log bindService -> Download-> unbindService->Download

onCreate链接建立DownloadingonDestroymBinder has been released

在Activity中的代码中,我们建立了一个 ServiceConnection 接口的匿名实现类, 在此接口我们用到了 onServiceConnected 方法。在这个方法中,有个 service IBinder类型的参数,该参数就是我们该TestService服务中声明的TestBinder的实例,我们将它向下转型后,就可以获取到TestBinder的实例。但是 onServiceConnected 方法时在与Service建立链接后采用获取到的。

当我们点击了BindService按钮后,会执行bindService方法,该方法有三个参数 第一个开启服务的Intent,第二个是 ServiceConnection 的匿名实现类(在与服务完成连接后,将会调用onServiceConnected方法),第三个是一个Flag位,BIND_AUTO_CREATE 表示,当链接到服务后服务会自动创建并执行 onCreate 方法。

当执行完bindService我们就可以拿到Binder对象了,这时候我们就可以与Service进行交互了。

如果想要解除绑定调用unbindService方法即可。

Bind方式开启服务的声明周期

image.png | left | 422x619

上图是通过Bind的方式开启的服务的声明周期,首先不相同的,Bind方式的声明周期并没有调用 onStartCommand 声明周期方法,仅仅是调用了onCreate方法,然就紧接着调用了onBind 方法获取Binder。这里我们需要注意一下。

并且Bind方式开启的服务的存活时间相对于Start方式开启的Service比较特殊,众所周知,Service并不是为某一个特定了Activity而提供的,而是在任意的地方都可以开启和结束。对同一个Service可以Bind多次,所以当有任何一个bind操作没有被unbind的话Service是不会被销毁的(即只存在任何与Service的链接,那么服务都不会被销毁),所以我们要注意Unbind Service,通常的做法是: 在Activity的onCreate方法中Bind Service 然后在Activity的onDestroy方法中Unbind Service。

override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContentView(R.layout.activity_main)    var bindingIntent = Intent(this, TestService::class.java)    this.bindService(bindingIntent, serviceConnection, android.app.Service.BIND_AUTO_CREATE)}override fun onDestroy() {    super.onDestroy()    this.unbindService(this.serviceConnection)}

结语

本文主要介绍了如何通过start方式和bind的方式开启服务以及各自的特点。正好篇幅也比较长了,正好就到此为止,接下来的内容将会在新的一章中继续学习,在下一张,将会学习start和bind结合的方式来开启服务。

转载于:https://www.cnblogs.com/slyfox/p/9366480.html

你可能感兴趣的文章
iOS8 Push Notifications
查看>>
各大名企笔试及面经大全(程序猿必读)
查看>>
Oracle 连接、会话数的查看,修改
查看>>
Oracle 11g password过期被锁定报道 ORA-28000 the account is locked
查看>>
轨磁条简介
查看>>
NSQ部署
查看>>
大厂前端高频面试问题与答案精选
查看>>
如何设计高扩展的在线网页制作平台
查看>>
Git 2.5增加了工作树、改进了三角工作流、性能等诸多方面
查看>>
Swift 5将强制执行内存独占访问
查看>>
中台之上(二):为什么业务架构存在20多年,技术人员还觉得它有点虚?
查看>>
深度揭秘腾讯云低功耗广域物联网LPWAN 技术及应用
查看>>
与Jeff Sutherland谈敏捷领导力
查看>>
More than React(四)HTML也可以静态编译?
查看>>
React Native最佳学习模版- F8 App开源了
查看>>
云服务正在吞噬世界!
查看>>
Web语义化标准解读
查看>>
一份代码构建移动、桌面、Web全平台应用
查看>>
高性能 Lua 技巧(译)
查看>>
区分指针、变量名、指针所指向的内存
查看>>