Android-认识Service

学习自

郭霖的博客

https://developer.android.google.cn/reference/android/app/Service#WhatIsAService

https://developer.android.google.cn/guide/components/services

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 withContext.startService() and Context.bindService().

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文件中声明

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--声明服务-->
<service android:name=".TestService" />
</application>

Step3: 开启服务

界面布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical"
tools:context="top.littledavid.studyservice.MainActivity"> <Button
android:id="@+id/startBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startService"
android:text="Start Service"
android:textAllCaps="false" /> <Button
android:id="@+id/stopBtn"
android:onClick="stopService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="Stop Service"
android:textAllCaps="false" /> </LinearLayout>

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如下:

onCreate
onStartCommand

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

onStartCommand

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

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

onDestroy
onCreate
onStartCommand

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

Start方式开启Service的生命周期

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

上图就是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,用来与服务交互

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical"
tools:context="top.littledavid.studyservice.MainActivity">
<!--OLD CODE-->
<Button
android:id="@+id/bindingServiceBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="bindingService"
android:text="Binding Service"
android:textAllCaps="false" /> <Button
android:id="@+id/unbindingBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:onClick="unbindingService"
android:text="Unbinding Service"
android:textAllCaps="false" /> <Button
android:id="@+id/downloadBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:onClick="downloadFile"
android:text="Download"
android:textAllCaps="false" /> </LinearLayout>

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
链接建立
Downloading
onDestroy
mBinder 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方式开启服务的声明周期

上图是通过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结合的方式来开启服务。

Android-认识Service的更多相关文章

  1. Android服务(Service)研究

    Service是android四大组件之一,没有用户界面,一直在后台运行. 为什么使用Service启动新线程执行耗时任务,而不直接在Activity中启动一个子线程处理? 1.Activity会被用 ...

  2. Android中Service 使用详解(LocalService + RemoteService)

    Service 简介: Service分为本地服务(LocalService)和远程服务(RemoteService): 1.本地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外L ...

  3. android 入门-Service实时向Activity通过BroadcastReceiver传递数据

    引文: http://www.cnblogs.com/linjiqin/p/3147764.html <RelativeLayout xmlns:android="http://sch ...

  4. android 入门-Service

    sdk 1.7 package com.example.hellowrold; import java.util.Random; import com.example.hellowrold.R.id; ...

  5. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

  6. Android中Service的使用

    我个人的理解是:我们平时使用的android系统的app的后台应用,就是这个原理 可以利用Service实现程序在后台运行,依照这个原理,可以通过Service来实现关键代码的运行与实现. <一 ...

  7. 【Android 】Service 全面总结

    1.Service的种类 按运行地点分类: 类别 区别  优点 缺点   应用 本地服务(Local) 该服务依附在主进程上,  服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外L ...

  8. Android Activity/Service/Broadcaster三大组件之间互相调用

    我们研究两个问题,1.Service如何通过Broadcaster更改activity的一个TextView.(研究这个问题,考虑到Service从服务器端获得消息之后,将msg返回给activity ...

  9. Android 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护

    本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context  ↳an ...

  10. Android 利用Service BroadcastReceiver实现小例子

    Activity: package com.example.test; import android.app.Activity; import android.content.Context; imp ...

随机推荐

  1. 构造方法和一般方法的区别(面试)-----java基础知识总结

    构造方法:对象创建时,就会调用与之对应的构造方法,对对象进行初始化: 一般方法:对象创建后,需要方法功能时才会调用. 构造方法,在对象创建时,会调用且只调用一次. 一般方法,对象创建后,可以被调用多次 ...

  2. Linux下使用cron让Python程序持久化运行

    正常情况下,一个python程序如果希望实现一直运行,不出错不奔溃是很难的,即使编译为可持续文件也是一样 幸运的是很多需求并不是需要24小时不间断运行,而是每隔一段时间运行一次即可 Linux系统自带 ...

  3. vim基本技巧

    一.无插件vim使用 1.查看修改代码 1)光标移动 h j k l    前下上后 w b       词首.词尾 ^ $       句首.句尾 2)编辑 x d r y p a i o .   ...

  4. jeecms常用的标签

    友情链接 <dt>友情链接:</dt> [@cms_friendlink_list] [#list tag_list as link] <dd><a href ...

  5. SQL记录-PLSQL包

    PL/SQL包 PL/SQL包是组逻辑相关的PL/SQL类型,变量和子程序模式对象. 程序包将有两个强制性的部分: 包装规范定义 包体或定义 包装规范定义 规范是接口到包.它只是声明的类型,变量,常量 ...

  6. mysql统计一个字段的多种状态

    假如我有下面的表:ID    Item           status            updatetime    author1    a        1        2014-01-0 ...

  7. [转]CSS浏览器兼容问题总结

    E6.0,ie7.0与Firefox的CSS兼容性问题1.DOCTYPE 影响 CSS 处理 2.FF: div 设置 margin-left, margin-right 为 auto 时已经居中,  ...

  8. 关于z-index这个层级的问题

    z-index它可真是一个神奇的东西,它可以随意安排你的层的叠加问题. 如你想让红色矩形压在蓝色矩形上,正常布局先建立一个红色的再建议一个蓝色的,就可以了. 但如果我相反来建立,那么就得借助z-ind ...

  9. TED_Topic10:The case for engineering our food

    By Pamela Ronald Pamela Ronald studies the genes that make plants more resistant to disease and stre ...

  10. BFS的队列

    按老师上课的话来总结,队列变化多端:   普通模板没有代价: 普通队列FIFO 01代价: 双端队列,单调队列 任意代价: 优先队列/堆,最短路SPFA/DIJKSTRA