學習 Android(十一)Service

簡介

在 Android 中,Service 是一種無界面的組件,用于在后臺執行長期運行跨進程的任務,如播放音樂、網絡下載或與遠程服務通信 。Service 可分為“啟動型(Started)”和“綁定型(Bound)”兩大類,它們在生命周期管理、調用方式和使用場景上各具特色 。下面將詳述 Service 的類型與生命周期,并通過示例演示其特點與運行流程。

1. Service 的基本概念

  • 什么是 Service

    Service 是 Android 四大組件之一(另包括 ActivityBroadcastReceiverContentProvider),它允許應用在后臺執行操作,即使切換到其他應用也能繼續運行。
    Service 沒有用戶界面,主要用于執行不需要用戶直接交互的任務,如播放音樂、上傳文件、定時同步等。

  • Service 與 Activity 的區別

    • 可見性:Activity 有界面并位于前臺;Service 無界面,在后臺運行。
    • 生命周期管理:Activity 生命周期由用戶導航驅動;Service 生命周期由調用組件或綁定狀態驅動。
    • 線程模型:默認在主線程執行,需要手動創建子線程以避免阻塞 UI。

2. Service 的類型

  • 啟動型 Service (Started Service)

    • 啟動方式:通過 startService(Intent) 調用。

    • 生命周期:調用 onCreate()onStartCommand() → (任務完成后)stopSelf() 或由外部 stopService() 停止 → onDestroy()

    • 特點:服務一旦啟動,即使啟動它的組件銷毀也會繼續運行,適合單次或周期性后臺任務。

  • 綁定型 Service (Bound Service)

    • 啟動方式:通過 bindService(Intent, ServiceConnection, flags) 調用。

    • 生命周期onCreate()onBind() → 與客戶端保持連接 → 客戶端 unbindService() 后 → onUnbind()onDestroy()

    • 特點:提供客戶端-服務端接口,允許 Activity 或其他組件調用服務方法并獲取返回結果,通常用于進程間通信(IPC)。

  • 前臺 Service (Foreground Service)

    • 在 Android O 及以上,需要在啟動時調用 startForeground() 并顯示持續通知,保證系統不會輕易回收。
    • 適用場景:音樂播放、導航、健康監測等用戶可見的重要服務。

3. Service 的生命周期

Android 官方將 Service 的生命周期分為兩條主路徑:StartedBound

  • 啟動型 Service 生命周期

    onCreate()↓
    onStartCommand()↓  (可多次調用 onStartCommand)
    stopService() 或 stopSelf()↓
    onDestroy()
    
    • onCreate():首次創建時調用,用于初始化資源。
    • onStartCommand():每次 startService() 調用后執行,返回值決定系統在被殺后如何重啟服務(START_STICKYSTART_NOT_STICKY 等)。
    • onDestroy():在 stopSelf()stopService() 后執行,釋放資源。
  • 綁定型 Service 生命周期

    onCreate()↓
    onBind()↓  (可多次 bind/unbind)
    onUnbind()↓
    onDestroy()
    
    • onBind():客戶端綁定時調用,返回 IBinder 用于客戶端調用服務方法。
    • onUnbind():最后一個客戶端解綁時調用,可決定是否再次允許綁定(返回 true 重寫 onRebind())。

4. Service 生命周期示例

  • MyService

    class MyService : Service() {private val tag = "ServiceLifecycle"private val binder = LocalBinder()// 用于綁定的 Binder 實現inner class LocalBinder : Binder() {fun getService(): MyService = this@MyService}override fun onCreate() {super.onCreate()Log.d(tag, "onCreate() called")}override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {Log.d(tag, "onStartCommand() called with startId: $startId")return START_STICKY}override fun onBind(intent: Intent): IBinder {Log.d(tag, "onBind() called")return binder}override fun onUnbind(intent: Intent?): Boolean {Log.d(tag, "onUnbind() called")return super.onUnbind(intent)}override fun onRebind(intent: Intent?) {super.onRebind(intent)Log.d(tag, "onRebind() called")}override fun onDestroy() {super.onDestroy()Log.d(tag, "onDestroy() called")}fun exampleMethod() {Log.d(tag, "Custom method called")}
    }
    

    記得要在 AndroidManifest.xml 文件中聲明

    <serviceandroid:name=".MyService"android:enabled="true"android:exported="true" />
    
  • activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><Buttonandroid:id="@+id/btn_start_service"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Start Service" /><Buttonandroid:id="@+id/btn_stop_service"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Stop Service" /><Buttonandroid:id="@+id/btn_bind_service"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Bind Service" /><Buttonandroid:id="@+id/btn_un_bind_service"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="UnBind Service" />
    </LinearLayout>
    
  • MainActivity

    import android.content.ComponentName
    import android.content.Context
    import android.content.Intent
    import android.content.ServiceConnection
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.os.IBinder
    import android.util.Log
    import android.widget.Buttonclass MainActivity : AppCompatActivity() {private val tag = "ServiceLifecycle"private var service: MyService? = nullprivate var isBound = falseprivate val btnStartService: Button by lazy { findViewById<Button>(R.id.btn_start_service) }private val btnStopService: Button by lazy { findViewById<Button>(R.id.btn_stop_service) }private val btnBindService: Button by lazy { findViewById<Button>(R.id.btn_bind_service) }private val btnUnbindService: Button by lazy { findViewById<Button>(R.id.btn_un_bind_service) }private val connection = object : ServiceConnection {override fun onServiceConnected(className: ComponentName, binder: IBinder) {Log.d(tag, "ServiceConnection.onServiceConnected()")val localBinder = binder as MyService.LocalBinderservice = localBinder.getService()isBound = trueservice?.exampleMethod()}override fun onServiceDisconnected(arg0: ComponentName) {Log.d(tag, "ServiceConnection.onServiceDisconnected()")isBound = false}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)Log.d(tag, "Activity onCreate()")// 按鈕點擊監聽btnStartService.setOnClickListener {val intent = Intent(this, MyService::class.java)startService(intent)}btnStopService.setOnClickListener {val intent = Intent(this, MyService::class.java)stopService(intent)}btnBindService.setOnClickListener {val intent = Intent(this, MyService::class.java)bindService(intent, connection, Context.BIND_AUTO_CREATE)}btnUnbindService.setOnClickListener {if (isBound) {unbindService(connection)isBound = false}}}override fun onDestroy() {super.onDestroy()Log.d(tag, "Activity onDestroy()")}
    }
    
    • 點擊 Start Service 后,再點擊 Stop Service

      onCreate() called
      onStartCommand() called with startId: 1onDestroy() called
      
    • 點擊 Bind Service 后,再點擊 Unbind Service

      onCreate() called
      onBind() called
      ServiceConnection.onServiceConnected()
      Custom method calledonUnbind() called
      onDestroy() called
      
    • 點擊 Start Service 后,再點擊 Bind Service 后, 再點擊 Stop Service 后,再點擊 UnBind Service

      點擊 Start Service
      onCreate() called
      onStartCommand() called with startId: 1點擊 Bind Service
      onBind() called
      ServiceConnection.onServiceConnected()
      Custom method called點擊 Stop Service
      無點擊 Unbind Service
      onUnbind() called
      

5. Service 常見面試題

  • 什么是 Service?它與 Thread 的區別是什么?

    答案:

    Service 是 Android 的四大組件之一,用于在后臺執行長時間運行的操作(如音樂播放、網絡請求),無需用戶界面。

    與 Thread 的區別:

    • Service 默認運行在主線程中,需要手動創建子線程處理耗時操作;Thread 是并發執行的基本單位。

    • Service 是系統組件,由系統管理生命周期;Thread 需開發者自行管理生命周期。

  • Service 的兩種啟動方式及區別?

    答案:

    • startService():通過?Intent?啟動,Service 會一直運行直到調用?stopSelf()?或外部調用?stopService()。適用于獨立后臺任務(如下載文件)。

    • bindService():通過?ServiceConnection?綁定,Service 生命周期與綁定組件(如 Activity)關聯。適用于交互場景(如音樂控制)。

  • 描述 Service 的生命周期方法(分啟動和綁定兩種情況)

    答案:

    • 僅?startService()onCreate()?→?onStartCommand()?→?running?→?stopSelf()?→?onDestroy()

    • 僅?bindService()onCreate()?→?onBind()?→?running?→?onUnbind()?→?onDestroy()

    • 混合啟動(先?startService()?再?bindService()):需同時調用?stopService()?和?unbindService()?才會銷毀。

  • onStartCommand() 的返回值有何意義?

    答案:

    返回值決定 Service 被系統殺死后的行為:

    • START_STICKY:系統重建 Service,但不保留 Intent。

    • START_NOT_STICKY:系統不主動重建。

    • START_REDELIVER_INTENT:系統重建 Service 并重新傳遞最后的 Intent。

  • 什么是前臺服務?如何實現?

    答案:

    • 前臺服務:需顯示通知(如音樂播放器),避免被系統殺死。

    • 實現:調用?startForeground(int id, Notification notification),需聲明?FOREGROUND_SERVICE?權限。

  • IntentService 的特點是什么?為什么被棄用?

    答案:

    • 特點:自動在子線程處理任務,任務完成后自動銷毀。

    • 棄用原因:Android 8.0(API 26)后限制后臺服務,推薦使用?JobIntentService?或?WorkManager

  • 如何保證 Service 不被殺死?

    答案:

    • 使用前臺服務并顯示通知。

    • onStartCommand()?返回?START_STICKY

    • 在?onDestroy()?中重啟 Service(不推薦,影響用戶體驗)。

  • Service 與 Activity 如何通信?

    答案:

    • 方式 1:通過?Binder(綁定服務時返回自定義 Binder 對象)。

    • 方式 2:使用?BroadcastReceiver?或?LiveData(解耦場景)。

    • 方式 3Messenger(跨進程通信)。

  • Android 8.0 后如何替代后臺服務?

    答案:

    • 使用?JobSchedulerWorkManager(兼容性更好)或前臺服務。后臺執行限制旨在優化電池壽命。
  • 音樂播放器為何用 Service 而不用 Thread?

    答案:

    • Service 作為獨立組件,生命周期不受 Activity 影響(如退出界面仍可播放)。Thread 隨 Activity 銷毀可能被終止,且無法直接跨界面控制。
  • 什么是粘性服務(Sticky Service)?

    答案:

    • 通過?startService()?啟動且?onStartCommand()?返回?START_STICKY?的服務,系統會在資源允許時嘗試重啟被殺死服務。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80787.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80787.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80787.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

投標環節:如何科學、合理地介紹 Elasticsearch 國產化替代方案——Easysearch?

一、Easysearch 定義 Easysearch 是由極限科技&#xff08;INFINI Labs&#xff09;自主研發的分布式搜索型數據庫&#xff0c;作為 Elasticsearch 的國產化替代方案&#xff0c;基于 Elasticsearch 7.10.2 開源版本深度優化[1]。 插一句&#xff1a;Elasticsearch 7.10.2 是里…

NVC++ 介紹與使用指南

文章目錄 NVC 介紹與使用指南NVC 簡介安裝 NVC基本使用編譯純 C 程序編譯 CUDA C 程序 關鍵編譯選項示例代碼使用標準并行算法 (STDPAR)混合 CUDA 和 C 優勢與限制優勢限制 調試與優化 NVC 介紹與使用指南 NVC 是 NVIDIA 提供的基于 LLVM 的 C 編譯器&#xff0c;專為 GPU 加速…

Veo 3 可以生成視頻,并附帶配樂

谷歌最新的視頻生成 AI 模型 Veo 3 可以創建與其生成的剪輯相配的音頻。 周二&#xff0c;在谷歌 I/O 2025 開發者大會上&#xff0c;谷歌發布了 Veo 3。該公司聲稱&#xff0c;這款產品可以生成音效、背景噪音&#xff0c;甚至對話&#xff0c;為其制作的視頻增添配樂。谷歌表…

Android本地語音識別引擎深度對比與集成指南:Vosk vs SherpaOnnx

技術選型對比矩陣 對比維度VoskSherpaOnnx核心架構基于Kaldi二次開發ONNX Runtime + K2新一代架構模型格式專用格式(需專用工具轉換)ONNX標準格式(跨框架通用)中文識別精度89.2% (TDNN模型)92.7% (Zipformer流式模型)內存占用60-150MB30-80MB遲表現320-500ms180-300ms多線程…

十四、Hive 視圖 Lateral View

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月20日 專欄&#xff1a;Hive教程 在Hive中&#xff0c;我們經常需要以不同于原始表結構的方式查看或處理數據。為了簡化復雜查詢、提供數據抽象&#xff0c;以及處理復雜數據類型&#xff08;如數組或Map&#xff09;&#…

微軟開源GraphRAG的使用教程-使用自定義數據測試GraphRAG

微軟在今年4月份的時候提出了GraphRAG的概念,然后在上周開源了GraphRAG,Github鏈接見https://github.com/microsoft/graphrag,截止當前,已有6900+Star。 安裝教程 官方推薦使用Python3.10-3.12版本,我使用Python3.10版本安裝時,在初始化項目過程中會報錯,切換到Python3.…

XXX企業云桌面系統建設技術方案書——基于超融合架構的安全高效云辦公平臺設計與實施

目錄 1. 項目背景與目標1.1 背景分析1.2 建設目標2. 需求分析2.1 功能需求用戶規模與場景終端兼容性2.2 非功能需求3. 系統架構設計3.1 總體架構圖流程圖說明3.2 技術選型對比3.3 網絡設計帶寬規劃公式4. 詳細實施方案4.1 分階段部署計劃4.2 桌面模板配置4.3 測試方案性能測試工…

數據直觀分析與可視化

數據直觀分析與可視化 一、數據的直觀分析核心價值 數據的直觀分析旨在通過視覺化的方式&#xff0c;幫助人們更直觀、更快速地理解數據的特征和模式&#xff0c;從而發現趨勢、異常值、分布情況以及變量之間的關系&#xff0c;為決策提供支持。 數據可視化與信息圖形、信息可…

Neo4j數據庫

Neo4j 是一款專門用來處理復雜關系的數據庫。我們可以簡單地將它理解為一個“用圖結構來管理數據的工具”。與我們常見的&#xff0c;像 Excel 那樣用表格&#xff08;行和列&#xff09;來存儲數據的傳統數據庫不同&#xff0c;Neo4j 采用了一種更接近人類思維對現實世界理解的…

Java異常處理全解析:從基礎到自定義

目錄 &#x1f680;前言&#x1f914;異常的定義與分類&#x1f4af;運行時異常&#x1f4af;編譯時異常&#x1f4af;異常的基本處理 &#x1f31f;異常的作用&#x1f427;自定義異常&#x1f4af;自定義運行時異常&#x1f4af;自定義編譯時異常 ??異常的處理方案&#x1…

Redisson分布式集合原理及應用

Redisson是一個用于Redis的Java客戶端&#xff0c;它簡化了復雜的數據結構和分布式服務的使用。 適用場景對比 數據結構適用場景優點RList消息隊列、任務隊列、歷史記錄分布式共享、阻塞操作、分頁查詢RMap緩存、配置中心、鍵值關聯數據支持鍵值對、分布式事務、TTLRSet去重集…

打破次元壁,VR 氣象站開啟氣象學習新姿勢?

在教育領域&#xff0c;VR 氣象站同樣發揮著巨大的作用&#xff0c;為氣象教學帶來了全新的模式&#xff0c;打破了傳統教學的次元壁&#xff0c;讓學生們以全新的姿勢學習氣象知識。? 在傳統的氣象教學中&#xff0c;學生們主要通過課本、圖片和老師的講解來學習氣象知識。這…

k8s面試題-ingress

場景&#xff1a;我通過deployment更新pod&#xff0c;ingress是怎么把新的請求流量發送到我新的pod的&#xff1f;是怎么監控到我更新的pod的&#xff1f; 在 Kubernetes 中&#xff0c;Ingress 是一種 API 對象&#xff0c;用于管理外部訪問到集群內服務的 HTTP 和 HTTPS 路…

RHCE 練習三:架設一臺 NFS 服務器

一、題目要求 1、開放 /nfs/shared 目錄&#xff0c;供所有用戶查詢資料 2、開放 /nfs/upload 目錄&#xff0c;為 192.168.xxx.0/24 網段主機可以上傳目錄&#xff0c;并將所有用戶及所屬的組映射為 nfs-upload,其 UID 和 GID 均為 210 3.將 /home/tom 目錄僅共享給 192.16…

【動態導通電阻】GaN HEMT動態導通電阻的精確測量

2023 年 7 月,瑞士洛桑聯邦理工學院的 Hongkeng Zhu 和 Elison Matioli 在《IEEE Transactions on Power Electronics》期刊發表了題為《Accurate Measurement of Dynamic ON-Resistance in GaN Transistors at Steady-State》的文章,基于提出的穩態測量方法,研究了氮化鎵(…

AI 制作游戲美術素材流程分享(程序員方向粗糙版)

AI 制作游戲美術素材分享(程序員方向粗糙版) 視頻講解: 抖音:https://www.douyin.com/user/self?from_tab_namemain&modal_id7505691614690561295&showTabpost Bilibili: https://www.bilibili.com/video/BV1ojJGzZEve/ 寫在最前面: 本方法比較粗糙,只對對美術風…

Java求職面試:互聯網大廠技術棧深度解析

文章簡述 在這篇文章中&#xff0c;我們將通過一個模擬的面試場景&#xff0c;帶你深入了解Java求職面試中可能會遇到的技術棧問題。通過這個故事&#xff0c;你可以學習到相關技術點的具體應用場景和面試技巧。 正文 場景&#xff1a;某互聯網大廠的面試現場 面試官&#…

學習日記-day11-5.20

完成目標&#xff1a; comment.java package com.zcr.pojo; import org.hibernate.annotations.GenericGenerator;import javax.persistence.*; //JPA操作表中數據&#xff0c;可以將對應的實體類映射到一張表上Entity(name "t_comment")//表示當前的實體類與哪張表…

機器學習第十九講:交叉驗證 → 用五次模擬考試驗證真實水平

機器學習第十九講&#xff1a;交叉驗證 → 用五次模擬考試驗證真實水平 資料取自《零基礎學機器學習》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的文章&#xff1a;DeepSeek R1本地與線上滿血版部署&#xff1a;超詳細手把手指南 交叉驗證…

Linux面試題集合(6)

創建多級目錄或者同級目錄 mkdir -p 文件名/文件名/文件名 mkdir -p 文件名 文件名 文件名 Linux創建一個文件 touch 文件名 DOS命令創建文件 echo 內容>文件名&#xff08;創建一個有內容的文件&#xff09; echo >文件名&#xff08;創建一個沒有內容的文件&#xff09…