Sitemap
Kamila Brito

Kamila Brito

Software Engineer

How to communicate service and UI using LiveData

In this post I will show how I solved a problem that I had recently in performing the communication between service and UI using LiveData.

2 min readMar 9, 2021

--

I recently had to use Android Services and it was many years since I needed to use this feature from our Android friend so I had to do a lot of research to remember how to communicate between the Service and the UI.

The answers to my research were well focused on communicating with UI through Handlers and Broadcast Receivers (all great solutions but they did not solve my situation). Because I am already using LiveData in my application, I decided to implement the same things to communicate with UI and as this solution worked really cool I decided to share it with you.

App

I created an example App to show how the communication between Service and UI works, which basically sends a string to the service, the string is updated in the service and then added to LiveData. LiveData is being “heard” on the Activity so when the updated string is added the Activity will be updated immediately.

Get Kamila Brito’s stories in your inbox

Join Medium for free to get updates from this writer.

Activity and Service

The activity will be responsible for starting the service and waiting for the result to be updated by LiveData.

class MainActivity : AppCompatActivity() {

private var messageObserver:Observer<String>? = null

override fun
onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setMessageObserver()

sendMessage.setOnClickListener {
setMessageObserver()
sendMessageToService(messageToSend.text.toString())
}
}

private fun sendMessageToService(message: String) {
val intentToService = Intent(this, MessageService::class.java)
intentToService.putExtra(SERVICE_INTENT_EXTRA, message)
this.startService(intentToService)
}

private fun setMessageObserver() {
messageObserver = Observer { message ->
serviceResponse.text = message
removeObserver()
}

messageObserver
?.let {
LiveDataManager.messageLiveData().observe(this,
it)
}
}

private fun removeObserver() {
messageObserver?.let {
LiveDataManager.messageLiveData().removeObserver(it)
}
}

companion object {
const val SERVICE_INTENT_EXTRA = "service_intent_extra_content"
}
}class MessageService: Service() {

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val ret = super.onStartCommand(intent, flags, startId)

intent?.getStringExtra(SERVICE_INTENT_EXTRA)?.let { data ->
val
returnMessage = "Service received message: $data"
LiveDataManager.updateBackendMessage(returnMessage)
}
return
ret
}

override fun onBind(intent: Intent?): IBinder? {
return null
}

}

LiveData

I decided to create my LiveData and manage it through a LiveDataManager.

class MessageLiveData : LiveData<String>() {
fun setMessage(message: String){
postValue(message)
}
}class LiveDataManager {

companion object {
private val messageLiveData = MessageLiveData()

fun updateBackendMessage(message: String) {
messageLiveData.setMessage(message)
}

fun messageLiveData() = messageLiveData

}
}

For more details of the implementation you can access the complete project on my GitHub.

--

--