Sobes.tech
Middle

Jak organizujesz interakcję między fragmentem a usługą w swojej aplikacji?

sobes.tech AI

Odpowiedź od AI

Wypiszę główne sposoby interakcji między fragmentem a serwisem:

  • Serwis powiązany (Bound Service): Fragment jest powiązany z serwisem, uzyskując bezpośredni dostęp do publicznych metod serwisu przez interfejs IBinder.
  • Serwis uruchomiony (Started Service): Fragment uruchamia serwis, wysyłając intencje (Intent) z danymi. W celu zwrotnej informacji serwis może wysyłać intencje broadcast lub używać ResultReceiver.
  • Intencje broadcast (BroadcastReceiver): Serwis wysyła intencje broadcast, a fragment je nasłuchuje za pomocą BroadcastReceiver.
  • Bus zdarzeń (np. GreenDao EventBus, Otto): Używany do wymiany zdarzeń między komponentami przez centralny dispatcher. Serwis publikuje zdarzenia, a fragment się na nie zapisuje.
  • LiveData: Fragment może obserwować obiekt LiveData w ViewModel, który z kolei współdziała z serwisem (np. przez repozytorium lub bezpośredni wywołanie metod powiązanego serwisu).

Przy wyborze metody uwzględniam:

  • Typ serwisu (powiązany lub uruchomiony).
  • Potrzebę dwukierunkowej interakcji.
  • Złożoność przesyłanych danych.
  • Cykl życia fragmentu i serwisu.
  • Czytelność i utrzymanie kodu.

Przykład powiązania fragmentu z serwisem:

// Fragment
private lateinit var myService: MyService
private var isBound = false

private val connection = object : ServiceConnection {
    override fun onServiceConnected(className: ComponentName, service: IBinder) {
        val binder = service as MyService.LocalBinder
        myService = binder.getService()
        isBound = true
    }

    override fun onServiceDisconnected(arg0: ComponentName) {
        isBound = false
    }
}

override fun onStart() {
    super.onStart()
    Intent(requireContext(), MyService::class.java).also { intent ->
        requireContext().bindService(intent, connection, Context.BIND_AUTO_CREATE)
    }
}

override fun onStop() {
    super.onStop()
    if (isBound) {
        requireContext().unbindService(connection)
        isBound = false
    }
}

Przykład wysyłania intencji broadcast z serwisu:

// Serwis
private fun sendUpdate(data: String) {
    Intent("my.app.SERVICE_UPDATE").apply {
        putExtra("data", data)
    }.also { intent ->
        sendBroadcast(intent)
    }
}

Przykład odbioru intencji broadcast w fragmencie:

// Fragment
private val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        when (intent?.action) {
            "my.app.SERVICE_UPDATE" -> {
                val data = intent.getStringExtra("data")
                // Przetwarzanie danych
            }
        }
    }
}

override fun onResume() {
    super.onResume()
    IntentFilter("my.app.SERVICE_UPDATE").also { filter ->
        requireContext().registerReceiver(receiver, filter)
    }
}

override fun onPause() {
    super.onPause()
    requireContext().unregisterReceiver(receiver)
}