首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Android Service 基礎全解析:啟動式與綁定式服務的生命周期與通信機制

     編輯:Java 綜合教學

前言

Service(服務)是 Android 四大組件之一,專門用於在後台執行長時間運行的操作,不提供用戶界面。根據啟動方式不同,Service 分為啟動式服務和綁定式服務,兩者生命周期、使用場景、通信機制截然不同。本文將通過原理講解、生命周期圖解、完整代碼實戰,幫助你徹底掌握 Service 核心用法。

一、兩類 Service 核心對比

維度啟動式服務綁定式服務
啟動方式startService(Intent)bindService(Intent, ServiceConnection, flags)
生命周期獨立於調用者,可長期運行依附於調用者,所有客戶端解綁即銷毀
停止方式stopSelf() 或 stopService()unbindService()
通信方式無直接通信通道(可用廣播/EventBus)IBinder 接口雙向通信
多客戶端多次 startService 不創建多實例支持多客戶端同時綁定
典型場景音樂播放、文件下載、定時任務進程間通信 (IPC)、客戶端需頻繁調用服務方法

Service 生命周期對比圖

二、啟動式服務完整實現

服務類

package com.jredu.helloworld.service;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;

public class MyService extends Service {
    private MediaPlayer mediaPlayer;

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化媒體播放器,載入原始資源
        mediaPlayer = MediaPlayer.create(this, R.raw.bieli); // 注意資源文件名建議用英文
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 啟動式服務核心邏輯入口
        mediaPlayer.start();
        // 返回標識決定服務被殺死後是否重建
        // START_STICKY: 被殺死後重建,intent 為 null
        // START_NOT_STICKY: 不重建
        // START_REDELIVER_INTENT: 重建並重傳最後一個 intent
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mediaPlayer.stop(); // 釋放資源
        mediaPlayer.release();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // 啟動式服務通常不綁定,返回 null
        return null;
    }
}

Activity 調用

// 啟動服務
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);

// 停止服務
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);

三、綁定式服務完整實現

1. 定義 IBinder 實現類(內部類模式)

public class MyService extends Service {
    private MediaPlayer mediaPlayer;
    
    // 自定義 Binder,暴露服務實例給客戶端
    public class MyBinder extends Binder {
        public MyService getService() {
            return MyService.this;
        }
    }
    private final IBinder binder = new MyBinder();

    @Override
    public IBinder onBind(Intent intent) {
        mediaPlayer.start();
        return binder; // 返回自定義 Binder
    }

    @Override
    public boolean onUnbind(Intent intent) {
        mediaPlayer.stop();
        return super.onUnbind(intent); // 返回 true 表示支持 rebind
    }
    
    // 業務方法供客戶端調用
    public void play() { mediaPlayer.start(); }
    public void pause() { mediaPlayer.pause(); }
    public boolean isPlaying() { return mediaPlayer.isPlaying(); }
}

2. Activity 綁定與通信

public class ServiceActivity extends AppCompatActivity {
    private Button btnBind, btnUnbind, btnStart, btnStop;
    private MyService myService;
    private boolean isBound = false;

    // ServiceConnection 監聽綁定狀態
    private final ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 獲取服務實例,建立通信通道
            MyService.MyBinder binder = (MyService.MyBinder) service;
            myService = binder.getService();
            isBound = true;
            // 現在可以直接調用 myService.play() 等方法
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 異常斷開(如服務崩潰),不會在正常 unbind 時調用
            isBound = false;
            myService = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service);
        
        btnBind = findViewById(R.id.bind);
        btnUnbind = findViewById(R.id.unbind);
        btnStart = findViewById(R.id.start);
        btnStop = findViewById(R.id.stop);

        btnBind.setOnClickListener(v -> {
            Intent intent = new Intent(this, MyService.class);
            // BIND_AUTO_CREATE: 服務不存在時自動創建
            bindService(intent, connection, Context.BIND_AUTO_CREATE);
        });

        btnUnbind.setOnClickListener(v -> {
            if (isBound) {
                unbindService(connection);
                isBound = false;
                myService = null;
            }
        });

        btnStart.setOnClickListener(v -> 
            startService(new Intent(this, MyService.class)));
        
        btnStop.setOnClickListener(v -> 
            stopService(new Intent(this, MyService.class)));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isBound) {
            unbindService(connection); // 防止內存洩漏
        }
    }
}

四、混合模式:同時啟動與綁定

實際開發中常見場景:音樂播放器需後台持續播放(啟動式),同時 UI 需控制播放/暫停/進度(綁定式)。

// 先啟動,保證服務存活
startService(new Intent(this, MyService.class));
// 再綁定,獲取通信通道
bindService(intent, connection, Context.BIND_AUTO_CREATE);

// 停止時:先解綁,再停止服務
unbindService(connection);
stopService(new Intent(this, MyService.class));

關鍵點:onStartCommand 返回 START_STICKY 確保服務被殺死後自動重啟;onUnbind 返回 true 支持 onRebind 重新綁定。

五、AndroidManifest.xml 註冊

<service 
    android:name=".service.MyService"
    android:enabled="true"
    android:exported="false" />  // exported=false 僅應用內部使用,跨進程需 true 並配置 intent-filter

六、最佳實踐與避坑指南

  • 避免 ANR:服務運行在主線程,耗時操作(網絡、IO、複雜計算)必須開啟子線程或使用 IntentService(已棄用,建議用 JobIntentService 或 WorkManager)
  • 內存洩漏防範:Activity 銷毀前務必 unbindService,否則 Service 持有 Activity 引用導致無法回收
  • 前台服務:Android 8.0+ 後台服務限制嚴格,長時間運行服務必須調用 startForeground() 顯示通知,否則幾分鐘後被系統殺死
  • 跨進程通信 (IPC):綁定式服務配合 AIDL 或 Messenger 實現多進程調用
  • 資源釋放:onDestroy 中釋放 MediaPlayer、關閉數據庫、取消定時器等

七、總結

Service 是 Android 後台計算的核心組件。掌握啟動式服務的獨立生命周期與綁定式服務的 IBinder 通信機制,並根據業務場景靈活選擇或組合使用,是開發高質量 Android 應用的必備技能。現代 Android 開發中,配合 WorkManager(可延遲任務)、Foreground Service(長時任務)、LiveData/Flow(數據觀察)能構建更健壯的後台處理架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved