• Android Service介绍


    一、什么是Service

    1、Service与Activity

            Service是后台运行,Activity是前台展示。

    2、Service定义 

    3、Service应用 

            可以应用到后台下载、地图定位、后台播放音乐等。 

    4、Service分类

            startService时Service才启动,与Activity的启停无关;bindService是与Activity绑定,一同启动和停止。

    二、Service的基本用法

    1、创建与配置Service

    • 新建Android工程,在功能目录右键新建Service(其中Exported代表应用程序组件能否调用Service或与其进行交互,默认为true;Enabled代表Service能否被实例化,默认为true)

    • 重写onBind、onCreate、onStartCommand和onDestory方法
    1. package com.study.service
    2. import android.app.Service
    3. import android.content.Intent
    4. import android.os.IBinder
    5. /**
    6. * 自定义Service.
    7. */
    8. class MyService : Service() {
    9. override fun onBind(intent: Intent): IBinder {
    10. TODO("Return the communication channel to the service.")
    11. }
    12. //Service创建时调用
    13. override fun onCreate() {
    14. super.onCreate()
    15. }
    16. //启动Service时调用
    17. override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    18. return super.onStartCommand(intent, flags, startId)
    19. }
    20. //Service销毁时调用
    21. override fun onDestroy() {
    22. super.onDestroy()
    23. }
    24. }
    • 在AndroidManifest.xml中配置Service
    1. <service
    2. android:name=".MyService"
    3. android:enabled="true"
    4. android:exported="true" />

    2、启动和停止Service

    3、startService生命周期

    4、代码示例

    activity_main.xml

    1. "1.0" encoding="utf-8"?>
    2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. xmlns:tools="http://schemas.android.com/tools"
    5. android:layout_width="match_parent"
    6. android:layout_height="match_parent"
    7. tools:context=".MainActivity">
    8. <androidx.appcompat.widget.AppCompatButton
    9. android:id="@+id/btn_start"
    10. android:layout_width="wrap_content"
    11. android:layout_height="wrap_content"
    12. android:text="启动服务"
    13. app:layout_constraintBottom_toBottomOf="parent"
    14. app:layout_constraintEnd_toEndOf="parent"
    15. app:layout_constraintHorizontal_bias="0.498"
    16. app:layout_constraintStart_toStartOf="parent"
    17. app:layout_constraintTop_toTopOf="parent"
    18. app:layout_constraintVertical_bias="0.336" />
    19. <androidx.appcompat.widget.AppCompatButton
    20. android:id="@+id/btn_stop"
    21. android:layout_width="wrap_content"
    22. android:layout_height="wrap_content"
    23. android:text="停止服务"
    24. app:layout_constraintBottom_toBottomOf="parent"
    25. app:layout_constraintEnd_toEndOf="parent"
    26. app:layout_constraintStart_toStartOf="parent"
    27. app:layout_constraintTop_toTopOf="parent" />
    28. androidx.constraintlayout.widget.ConstraintLayout>

    MainActivity.kt

    1. package com.study.service
    2. import android.content.Intent
    3. import androidx.appcompat.app.AppCompatActivity
    4. import android.os.Bundle
    5. import android.view.View
    6. import androidx.appcompat.widget.AppCompatButton
    7. class MainActivity : AppCompatActivity() {
    8. private lateinit var btnStart : AppCompatButton
    9. private lateinit var btnStop : AppCompatButton
    10. override fun onCreate(savedInstanceState: Bundle?) {
    11. super.onCreate(savedInstanceState)
    12. setContentView(R.layout.activity_main)
    13. btnStart = findViewById(R.id.btn_start)
    14. btnStop = findViewById(R.id.btn_stop)
    15. btnStart.setOnClickListener {
    16. //启动Service
    17. val intent = Intent(this, MyService::class.java)
    18. startService(intent)
    19. }
    20. btnStop.setOnClickListener {
    21. //停止Service
    22. val intent = Intent(this, MyService::class.java)
    23. stopService(intent)
    24. }
    25. }
    26. }

    MyService.kt

    1. package com.study.service
    2. import android.app.ActivityManager
    3. import android.app.Service
    4. import android.content.Context
    5. import android.content.Intent
    6. import android.os.IBinder
    7. import android.util.Log
    8. /**
    9. * 自定义Service.
    10. */
    11. class MyService : Service() {
    12. override fun onBind(intent: Intent): IBinder {
    13. TODO("Return the communication channel to the service.")
    14. }
    15. //Service创建时调用
    16. override fun onCreate() {
    17. Log.e("MyService", "onCreate: Service已创建")
    18. super.onCreate()
    19. }
    20. //启动Service时调用
    21. override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    22. Log.e("MyService", "onCreate: Service已启动")
    23. Thread {
    24. var i = 0
    25. while (isRunning()) {
    26. Log.e("MyService", (++i).toString())
    27. Thread.sleep(1000)
    28. }
    29. }.start()
    30. return super.onStartCommand(intent, flags, startId)
    31. }
    32. //Service销毁时调用
    33. override fun onDestroy() {
    34. Log.e("MyService", "onCreate: Service已停止")
    35. super.onDestroy()
    36. }
    37. /**
    38. * 判断Service是否正在运行.
    39. */
    40. private fun isRunning(): Boolean {
    41. //获取Activity管理器
    42. val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    43. //获取所有正在运行的Service
    44. val runningService =
    45. activityManager.getRunningServices(60) as ArrayList
    46. runningService.forEach {
    47. if (it.service.className == "com.study.service.MyService")
    48. return true
    49. }
    50. return false
    51. }
    52. }

    三、Service的基本用法实例(实现后台音乐播放和停止)

    activity_main.xml

    1. "1.0" encoding="utf-8"?>
    2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. xmlns:tools="http://schemas.android.com/tools"
    5. android:layout_width="match_parent"
    6. android:layout_height="match_parent"
    7. tools:context=".MainActivity">
    8. <androidx.appcompat.widget.AppCompatButton
    9. android:id="@+id/btn_stop"
    10. android:layout_width="115dp"
    11. android:layout_height="52dp"
    12. android:text="暂停"
    13. app:layout_constraintBottom_toBottomOf="parent"
    14. app:layout_constraintEnd_toEndOf="parent"
    15. app:layout_constraintHorizontal_bias="0.498"
    16. app:layout_constraintStart_toStartOf="parent"
    17. app:layout_constraintTop_toTopOf="parent"
    18. app:layout_constraintVertical_bias="0.461" />
    19. <androidx.appcompat.widget.AppCompatButton
    20. android:id="@+id/btn_start"
    21. android:layout_width="118dp"
    22. android:layout_height="59dp"
    23. android:text="播放"
    24. app:layout_constraintBottom_toBottomOf="parent"
    25. app:layout_constraintEnd_toEndOf="parent"
    26. app:layout_constraintHorizontal_bias="0.498"
    27. app:layout_constraintStart_toStartOf="parent"
    28. app:layout_constraintTop_toTopOf="parent"
    29. app:layout_constraintVertical_bias="0.322" />
    30. androidx.constraintlayout.widget.ConstraintLayout>

    MainActivity.kt

    1. package com.study.service
    2. import android.content.Intent
    3. import android.os.Bundle
    4. import androidx.appcompat.app.AppCompatActivity
    5. import androidx.appcompat.widget.AppCompatButton
    6. /**
    7. * 控制页面.
    8. */
    9. class MainActivity : AppCompatActivity() {
    10. private lateinit var btnStart: AppCompatButton
    11. private lateinit var btnStop: AppCompatButton
    12. override fun onCreate(savedInstanceState: Bundle?) {
    13. super.onCreate(savedInstanceState)
    14. setContentView(R.layout.activity_main)
    15. btnStart = findViewById(R.id.btn_start)
    16. btnStop = findViewById(R.id.btn_stop)
    17. btnStart.setOnClickListener {
    18. //启动音乐播放服务
    19. startService(Intent(this, MusicService::class.java))
    20. }
    21. btnStop.setOnClickListener {
    22. //关闭音乐播放服务
    23. stopService(Intent(this, MusicService::class.java))
    24. }
    25. }
    26. override fun onStart() {
    27. //启动页面播放音乐
    28. startService(Intent(this, MusicService::class.java))
    29. super.onStart()
    30. }
    31. }

    MusicService.kt

    1. package com.study.service
    2. import android.app.Service
    3. import android.content.Intent
    4. import android.media.MediaPlayer
    5. import android.os.IBinder
    6. /**
    7. * 音乐播放服务.
    8. */
    9. class MusicService : Service() {
    10. companion object {
    11. //静态对象:记录当前播放状态
    12. var isPlay: Boolean = false
    13. }
    14. //音乐播放对象
    15. private lateinit var mediaPlayer: MediaPlayer
    16. override fun onBind(intent: Intent?): IBinder? {
    17. TODO("Not yet implemented")
    18. }
    19. override fun onCreate() {
    20. //创建MediaPlayer对象,并加载音频文件
    21. mediaPlayer = MediaPlayer.create(this, R.raw.music)
    22. super.onCreate()
    23. }
    24. override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    25. //判断音乐是否播放中
    26. if (!mediaPlayer.isPlaying) {
    27. //播放音乐
    28. mediaPlayer.start()
    29. //记录播放状态
    30. isPlay = mediaPlayer.isPlaying
    31. }
    32. return super.onStartCommand(intent, flags, startId)
    33. }
    34. override fun onDestroy() {
    35. //停止播放
    36. mediaPlayer.stop()
    37. //记录播放状态
    38. isPlay = mediaPlayer.isPlaying
    39. //释放资源
    40. mediaPlayer.release()
    41. super.onDestroy()
    42. }
    43. }

    四、Bound Service(绑定Service)

            之前的startService,Activity与Service之前没有太大的联系,无法进行通信和交换数据;而boundService,Activity与Service之间可以进行数据交互和方法调用。

     1、boundService生命周期

     2、boundService基本步骤

    3、boundService实例(模拟双色球)

    activity_main.xml

    1. "1.0" encoding="utf-8"?>
    2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. xmlns:tools="http://schemas.android.com/tools"
    5. android:layout_width="match_parent"
    6. android:layout_height="match_parent"
    7. tools:context=".MainActivity">
    8. <androidx.appcompat.widget.AppCompatTextView
    9. android:id="@+id/tv6"
    10. android:layout_width="wrap_content"
    11. android:layout_height="wrap_content"
    12. android:text="00"
    13. app:layout_constraintBottom_toBottomOf="parent"
    14. app:layout_constraintHorizontal_bias="0.85"
    15. app:layout_constraintLeft_toLeftOf="parent"
    16. app:layout_constraintRight_toRightOf="parent"
    17. app:layout_constraintTop_toTopOf="parent"
    18. app:layout_constraintVertical_bias="0.323" />
    19. <androidx.appcompat.widget.AppCompatTextView
    20. android:id="@+id/tv5"
    21. android:layout_width="wrap_content"
    22. android:layout_height="wrap_content"
    23. android:text="00"
    24. app:layout_constraintBottom_toBottomOf="parent"
    25. app:layout_constraintHorizontal_bias="0.726"
    26. app:layout_constraintLeft_toLeftOf="parent"
    27. app:layout_constraintRight_toRightOf="parent"
    28. app:layout_constraintTop_toTopOf="parent"
    29. app:layout_constraintVertical_bias="0.323" />
    30. <androidx.appcompat.widget.AppCompatTextView
    31. android:id="@+id/tv4"
    32. android:layout_width="wrap_content"
    33. android:layout_height="wrap_content"
    34. android:text="00"
    35. app:layout_constraintBottom_toBottomOf="parent"
    36. app:layout_constraintHorizontal_bias="0.61"
    37. app:layout_constraintLeft_toLeftOf="parent"
    38. app:layout_constraintRight_toRightOf="parent"
    39. app:layout_constraintTop_toTopOf="parent"
    40. app:layout_constraintVertical_bias="0.323" />
    41. <androidx.appcompat.widget.AppCompatTextView
    42. android:id="@+id/tv3"
    43. android:layout_width="wrap_content"
    44. android:layout_height="wrap_content"
    45. android:text="00"
    46. app:layout_constraintBottom_toBottomOf="parent"
    47. app:layout_constraintHorizontal_bias="0.498"
    48. app:layout_constraintLeft_toLeftOf="parent"
    49. app:layout_constraintRight_toRightOf="parent"
    50. app:layout_constraintTop_toTopOf="parent"
    51. app:layout_constraintVertical_bias="0.323" />
    52. <androidx.appcompat.widget.AppCompatTextView
    53. android:id="@+id/tv2"
    54. android:layout_width="wrap_content"
    55. android:layout_height="wrap_content"
    56. android:text="00"
    57. app:layout_constraintBottom_toBottomOf="parent"
    58. app:layout_constraintHorizontal_bias="0.374"
    59. app:layout_constraintLeft_toLeftOf="parent"
    60. app:layout_constraintRight_toRightOf="parent"
    61. app:layout_constraintTop_toTopOf="parent"
    62. app:layout_constraintVertical_bias="0.323" />
    63. <androidx.appcompat.widget.AppCompatTextView
    64. android:id="@+id/tv7"
    65. android:layout_width="wrap_content"
    66. android:layout_height="wrap_content"
    67. android:text="00"
    68. app:layout_constraintBottom_toBottomOf="parent"
    69. app:layout_constraintHorizontal_bias="0.255"
    70. app:layout_constraintLeft_toLeftOf="parent"
    71. app:layout_constraintRight_toRightOf="parent"
    72. app:layout_constraintTop_toTopOf="parent"
    73. app:layout_constraintVertical_bias="0.323" />
    74. <androidx.appcompat.widget.AppCompatTextView
    75. android:id="@+id/tv1"
    76. android:layout_width="wrap_content"
    77. android:layout_height="wrap_content"
    78. android:text="00"
    79. app:layout_constraintBottom_toBottomOf="parent"
    80. app:layout_constraintHorizontal_bias="0.128"
    81. app:layout_constraintLeft_toLeftOf="parent"
    82. app:layout_constraintRight_toRightOf="parent"
    83. app:layout_constraintTop_toTopOf="parent"
    84. app:layout_constraintVertical_bias="0.323" />
    85. <androidx.appcompat.widget.AppCompatButton
    86. android:id="@+id/btn_start"
    87. android:layout_width="wrap_content"
    88. android:layout_height="wrap_content"
    89. android:text="生成随机数"
    90. app:layout_constraintBottom_toBottomOf="parent"
    91. app:layout_constraintEnd_toEndOf="parent"
    92. app:layout_constraintStart_toStartOf="parent"
    93. app:layout_constraintTop_toTopOf="parent" />
    94. androidx.constraintlayout.widget.ConstraintLayout>

    BinderService.kt

    1. package com.study.bindservice
    2. import android.app.Service
    3. import android.content.Intent
    4. import android.os.Binder
    5. import android.os.IBinder
    6. import kotlin.random.Random
    7. /**
    8. * 随机数生成服务.
    9. */
    10. class BinderService : Service() {
    11. //1. 创建MyBinder内部类
    12. class MyBinder : Binder() {
    13. //1.1. 获取Service方法
    14. fun getService(): BinderService {
    15. //1.2. 返回当前Service
    16. return BinderService()
    17. }
    18. }
    19. override fun onBind(intent: Intent?): IBinder {
    20. //2. 返回MyBinder Service对象
    21. return MyBinder()
    22. }
    23. override fun onDestroy() {
    24. //3. 销毁Service
    25. super.onDestroy()
    26. }
    27. //返回随机数方法.
    28. fun getRandomNumber(): List {
    29. val resArr = mutableListOf()
    30. var strNumber = ""
    31. for (i in 0 until 7) {
    32. val number = Random.nextInt(33) + 1
    33. strNumber = if (number < 10) {
    34. "0$number"
    35. } else {
    36. number.toString()
    37. }
    38. resArr.add(strNumber)
    39. }
    40. return resArr
    41. }
    42. }

    MainActivity.kt

    1. package com.study.bindservice
    2. import android.content.ComponentName
    3. import android.content.Intent
    4. import android.content.ServiceConnection
    5. import android.os.Bundle
    6. import android.os.IBinder
    7. import androidx.appcompat.app.AppCompatActivity
    8. import androidx.appcompat.widget.AppCompatButton
    9. import androidx.appcompat.widget.AppCompatTextView
    10. class MainActivity : AppCompatActivity() {
    11. private lateinit var btnStart: AppCompatButton
    12. private lateinit var binderService: BinderService
    13. private val tvId =
    14. mutableListOf(R.id.tv1, R.id.tv2, R.id.tv3, R.id.tv4, R.id.tv5, R.id.tv6, R.id.tv7)
    15. override fun onCreate(savedInstanceState: Bundle?) {
    16. super.onCreate(savedInstanceState)
    17. setContentView(R.layout.activity_main)
    18. btnStart = findViewById(R.id.btn_start)
    19. btnStart.setOnClickListener {
    20. val number = binderService.getRandomNumber()
    21. number.forEachIndexed { index, it ->
    22. val textViewCompat = findViewById(tvId[index])
    23. textViewCompat.text = it
    24. }
    25. }
    26. }
    27. //4. 创建ServiceConnection对象
    28. private var conn = object : ServiceConnection {
    29. //Service与绑定它的组件连接成功时调用
    30. override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
    31. //4.1 获取后台service
    32. binderService = (service as BinderService.MyBinder).getService()
    33. }
    34. //Service与绑定它的组件断开连接时调用
    35. override fun onServiceDisconnected(name: ComponentName?) {
    36. }
    37. }
    38. //5. 绑定服务
    39. override fun onStart() {
    40. super.onStart()
    41. val intent = Intent(this, BinderService::class.java)
    42. bindService(intent, conn, BIND_AUTO_CREATE)
    43. }
    44. //6. 解除绑定
    45. override fun onStop() {
    46. super.onStop()
    47. unbindService(conn)
    48. }
    49. }

    五、IntentService

            IntentService在Android8.0以后已被弃用,目前官方推荐使用Jetpack组件。

    1、为什么要使用IntentService

            它可以自动开启线程来执行耗时任务,并且在耗时任务执行完毕之后可以自动停止服务。

     2、IntentService实例

    activity_main.xml

    1. "1.0" encoding="utf-8"?>
    2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. xmlns:tools="http://schemas.android.com/tools"
    5. android:layout_width="match_parent"
    6. android:layout_height="match_parent"
    7. tools:context=".MainActivity">
    8. <androidx.appcompat.widget.AppCompatButton
    9. android:id="@+id/btn_intent_service"
    10. android:layout_width="wrap_content"
    11. android:layout_height="wrap_content"
    12. android:text="启动IntentService"
    13. app:layout_constraintBottom_toBottomOf="parent"
    14. app:layout_constraintEnd_toEndOf="parent"
    15. app:layout_constraintStart_toStartOf="parent"
    16. app:layout_constraintTop_toTopOf="parent"
    17. app:layout_constraintVertical_bias="0.528" />
    18. <androidx.appcompat.widget.AppCompatButton
    19. android:id="@+id/btn_service"
    20. android:layout_width="wrap_content"
    21. android:layout_height="wrap_content"
    22. android:text="启动Service"
    23. app:layout_constraintBottom_toBottomOf="parent"
    24. app:layout_constraintEnd_toEndOf="parent"
    25. app:layout_constraintStart_toStartOf="parent"
    26. app:layout_constraintTop_toTopOf="parent"
    27. app:layout_constraintVertical_bias="0.288" />
    28. androidx.constraintlayout.widget.ConstraintLayout>

    MainActivity.kt

    1. package com.study.intent.service
    2. import android.content.Intent
    3. import android.os.Bundle
    4. import androidx.appcompat.app.AppCompatActivity
    5. import androidx.appcompat.widget.AppCompatButton
    6. class MainActivity : AppCompatActivity() {
    7. override fun onCreate(savedInstanceState: Bundle?) {
    8. super.onCreate(savedInstanceState)
    9. setContentView(R.layout.activity_main)
    10. val btnService = findViewById(R.id.btn_service)
    11. val btnIntentService = findViewById(R.id.btn_intent_service)
    12. //启动普通Service
    13. btnService.setOnClickListener {
    14. startService(Intent(this, MyService::class.java))
    15. }
    16. //启动IntentService
    17. btnIntentService.setOnClickListener {
    18. startService(Intent(this, MyIntentService::class.java))
    19. }
    20. }
    21. }

    MyService.kt

    1. package com.study.intent.service
    2. import android.app.Service
    3. import android.content.Intent
    4. import android.os.IBinder
    5. import android.util.Log
    6. /**
    7. * 普通Service.
    8. */
    9. class MyService: Service() {
    10. companion object{
    11. const val TAG = "MyService"
    12. }
    13. override fun onBind(intent: Intent?): IBinder? {
    14. TODO("Not yet implemented")
    15. }
    16. override fun onCreate() {
    17. Log.e(TAG, "onCreate: Service已创建")
    18. super.onCreate()
    19. }
    20. override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    21. Log.e(TAG, "onStartCommand: Service已启动")
    22. //进行耗时操作(需要在子线程中进行)
    23. Thread {
    24. val endTime = System.currentTimeMillis() + 20 * 1000
    25. while (System.currentTimeMillis() < endTime) {
    26. synchronized(this) {
    27. endTime - System.currentTimeMillis()
    28. }
    29. }
    30. //不能自动停止服务,需要代码停止
    31. stopSelf()
    32. }.start()
    33. return super.onStartCommand(intent, flags, startId)
    34. }
    35. override fun onDestroy() {
    36. Log.e(TAG, "onDestroy: Service已销毁")
    37. super.onDestroy()
    38. }
    39. }

    MyIntentService.kt

    1. package com.study.intent.service
    2. import android.app.IntentService
    3. import android.content.Intent
    4. import android.util.Log
    5. /**
    6. * IntentService.
    7. */
    8. class MyIntentService(name: String?) : IntentService(name) {
    9. companion object {
    10. const val TAG = "MyIntentService"
    11. }
    12. //默认的构造方法.
    13. constructor() : this("")
    14. override fun onHandleIntent(intent: Intent?) {
    15. //自动开启线程执行耗时任务
    16. Log.e(TAG, "onHandleIntent: Service已启动")
    17. val endTime = System.currentTimeMillis() + 20 * 1000
    18. while (System.currentTimeMillis() < endTime) {
    19. synchronized(this) {
    20. endTime - System.currentTimeMillis()
    21. }
    22. }
    23. }
    24. override fun onDestroy() {
    25. //自动销毁
    26. Log.e(TAG, "onDestroy: Service已销毁")
    27. super.onDestroy()
    28. }
    29. }

  • 相关阅读:
    试题:最大的矩形(给定直方图里面积最大的矩形)
    2023品牌新媒体矩阵营销洞察报告:流量内卷下,如何寻找增长新引擎?
    山东大学项目实训(二十七)—— 微信小程序开发总结,一年时间真的可以改变一个人很多
    docker安装RabbitMQ及安装延迟插件
    mysql索引入门-黑马
    Tomcat 学习笔记及常见问题解决
    Go语言实践案例之猜谜游戏| 青训营
    flask 框架web开发视频笔记
    营丘福稻品牌山东大米 国稻种芯·中国水稻节:淄博高青招牌
    Java 项目防止 SQL 注入的四种方案
  • 原文地址:https://blog.csdn.net/weixin_43192102/article/details/126368969