← Назад к вопросам

Для чего нужен Bound Service?

1.7 Middle🔥 141 комментариев
#Android компоненты

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Bound Service - коммуникация между компонентами

Bound Service - это сервис, который позволяет другим компонентам (Activity, другому Service) подключиться к нему и общаться через интерфейс. Это отличается от обычного Service, который просто выполняет работу в фоне.

Два типа Service

Started Service        Bound Service
┌─────────────────┐   ┌──────────────────┐
│ Фоновая работа  │   │ Коммуникация     │
│ Независимо      │   │ Связь с Activity │
│ Работает пока   │   │ Request/Response │
│ не stopService()│   │ Привязана к      │
│                 │   │ жизненному цику  │
└─────────────────┘   └──────────────────┘

Как работает Bound Service

// 1. Создание сервиса
class MusicService : Service() {
    private val binder = MusicBinder()
    
    override fun onBind(intent: Intent?): IBinder {
        return binder  // возвращаем интерфейс для связи
    }
    
    // Интерфейс для коммуникации
    inner class MusicBinder : Binder() {
        fun getService(): MusicService = this@MusicService
    }
    
    fun play(song: String) {
        Log.d("Music", "Playing: $song")
    }
    
    fun stop() {
        Log.d("Music", "Stopped")
    }
}

// 2. Подключение к сервису
class MainActivity : AppCompatActivity() {
    private var musicService: MusicService? = null
    private var isBound = false
    
    private val connection = object : ServiceConnection {
        override fun onServiceConnected(
            name: ComponentName,
            service: IBinder
        ) {
            val binder = service as MusicService.MusicBinder
            musicService = binder.getService()
            isBound = true
            Log.d("MainActivity", "Service connected")
        }
        
        override fun onServiceDisconnected(name: ComponentName) {
            isBound = false
            Log.d("MainActivity", "Service disconnected")
        }
    }
    
    override fun onStart() {
        super.onStart()
        // Подключаемся к сервису
        Intent(this, MusicService::class.java).also { intent ->
            bindService(intent, connection, Context.BIND_AUTO_CREATE)
        }
    }
    
    override fun onStop() {
        super.onStop()
        // Отключаемся когда Activity скрывается
        if (isBound) {
            unbindService(connection)
            isBound = false
        }
    }
    
    fun playMusic() {
        musicService?.play("MySong.mp3")
    }
}

Когда использовать Bound Service

1. Медиа плеер

// Сервис воспроизводит музыку
// Activity управляет playback через bound service
class MediaService : Service() {
    private var mediaPlayer: MediaPlayer? = null
    
    fun play(uri: String) {
        mediaPlayer = MediaPlayer().apply {
            setDataSource(uri)
            prepare()
            start()
        }
    }
    
    fun pause() = mediaPlayer?.pause()
    fun resume() = mediaPlayer?.start()
}

2. Синхронизация данных

// Activity может запросить статус синхронизации
class SyncService : Service() {
    private var syncInProgress = false
    
    fun startSync() {
        syncInProgress = true
        // начать синхронизацию
    }
    
    fun getSyncStatus(): Boolean = syncInProgress
}

3. Шифрование/Криптография

// Сервис для безопасных операций
class CryptoService : Service() {
    fun encrypt(data: String): String {
        // криптографическая операция
        return encryptionHelper.encrypt(data)
    }
    
    fun decrypt(encrypted: String): String {
        return encryptionHelper.decrypt(encrypted)
    }
}

4. Работа с GPS

class LocationService : Service() {
    private var currentLocation: Location? = null
    
    fun getLocation(): Location? = currentLocation
    
    fun startTracking() {
        // начать отслеживание локации
    }
}

AIDL - для межпроцессной коммуникации

Если нужна коммуникация между приложениями:

// В build.gradle
// Создаём файл .aidl

// IRemoteService.aidl
package com.example.myservice;

interface IRemoteService {
    void doSomething();
    String getData();
}

// Сервис реализует интерфейс
class RemoteService : Service() {
    private val stub = object : IRemoteService.Stub() {
        override fun doSomething() {
            Log.d("Remote", "Something done")
        }
        
        override fun getData(): String {
            return "Remote data"
        }
    }
    
    override fun onBind(intent: Intent?): IBinder = stub
}

// Другое приложение может подключиться
class ClientActivity : AppCompatActivity() {
    private var remoteService: IRemoteService? = null
    
    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            remoteService = IRemoteService.Stub.asInterface(service)
        }
        
        override fun onServiceDisconnected(name: ComponentName) {
            remoteService = null
        }
    }
}

Жизненный цикл Bound Service

onCreate()
   ↓
onBind()  ← запрос от Activity
   ↓
(Service работает)
   ↓
onUnbind() ← Activity отключилась
   ↓
onDestroy()

Отличие от Started Service:

  • Bound Service живёт столько же, сколько подключены клиенты
  • Когда все клиенты отключились, сервис может быть уничтожен
  • Started Service работает независимо до явного stopService()

Практический пример - Медиа плеер

// Service
class MusicPlaybackService : Service() {
    private var mediaPlayer: MediaPlayer? = null
    private val binder = MusicBinder()
    private var currentTrack: String = ""
    
    inner class MusicBinder : Binder() {
        fun getService() = this@MusicPlaybackService
    }
    
    override fun onBind(intent: Intent?): IBinder = binder
    
    fun play(track: String) {
        currentTrack = track
        mediaPlayer = MediaPlayer().apply {
            setDataSource(track)
            prepare()
            start()
        }
    }
    
    fun pause() = mediaPlayer?.pause()
    fun resume() = mediaPlayer?.start()
    fun stop() = mediaPlayer?.stop()
    fun getCurrentTrack() = currentTrack
    fun isPlaying() = mediaPlayer?.isPlaying ?: false
}

// Activity
class PlayerActivity : AppCompatActivity() {
    private var musicService: MusicPlaybackService? = null
    private var isBound = false
    
    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            val binder = service as MusicPlaybackService.MusicBinder
            musicService = binder.getService()
            isBound = true
            updateUI()
        }
        
        override fun onServiceDisconnected(name: ComponentName) {
            isBound = false
        }
    }
    
    override fun onStart() {
        super.onStart()
        bindService(
            Intent(this, MusicPlaybackService::class.java),
            connection,
            Context.BIND_AUTO_CREATE
        )
    }
    
    override fun onStop() {
        super.onStop()
        if (isBound) {
            unbindService(connection)
            isBound = false
        }
    }
    
    fun playButtonClick() {
        musicService?.play("/storage/music/song.mp3")
    }
    
    private fun updateUI() {
        val track = musicService?.getCurrentTrack()
        val isPlaying = musicService?.isPlaying() ?: false
        // обновляем UI
    }
}

Вывод

Bound Service используется когда:

  • Нужна двусторонняя коммуникация между Activity и Service
  • Request/Response модель - Activity запрашивает данные
  • Тесная связь - Service зависит от подключённых клиентов
  • Медиа плеер, GPS, сдвиг данных - типичные примеры

Отличается от Started Service тем, что:

  • Привязан к жизненному циклу клиентов
  • Прекращает работу когда все отключились
  • Позволяет вызывать методы сервиса из Activity