Michael
Michael

Reputation: 593

How to handle errors with liveData

In my app, I have this flow:

ClickListender in my fragment:

  search_button.setOnClickListener {
        if(search_input.text.isNullOrEmpty())
            Toast.makeText(activity, "Input Error", Toast.LENGTH_LONG).show()
        else
            viewModel.onSearchButtonClicked(search_input.text.toString())
    }

onSearchButtonClicked inside viewModel:

    fun onSearchButtonClicked(input: String) {
        coroutineScope.launch {
   repo.insertToDatabase(input)
        }
    }

insertToDatabase inside Repository:

   suspend fun insertToDatabase(string: String) {
        withContext(Dispatchers.IO) {
            val dataList =
                ExternalApi.retrofitCall.getData(string).await()
            if (dataList.intialDataResult < 1) {
                //show error
            } else {
                //all good
                database.myDataBase.insertAll(dataList)
            }
        }
    }

I need to show error message if intialDataResult is less then one. I thought about create MutableLiveData inside my repository with initial value of false and listen from the fragment through the viewModel, but it's not good approach because I have no way to set the LiveData to "false" again after I show error message.

I also tried to return bool from the insertToDatabase function and decide if to show error or not, with no success.

Any ideas how can I solve this?

Upvotes: 3

Views: 1017

Answers (1)

rupinderjeet
rupinderjeet

Reputation: 2838

Why not create a LiveData to manage your work's result state?

Create a class to store result of work why sealed class?

sealed class ResultState{
    object Success: ResultState() // this is object because I added no params
    data class Failure(val message: String): ResultState()
}

Create a LiveData to report this result

val stateLiveData = MutableLiveData<ResultState>()

Make insertToDatabase() return a result

suspend fun insertToDatabase(input: String): ResultState {
    return withContext<ResultState>(Dispatchers.IO) {

        val dataList =
            ExternalApi.retrofitCall.getData(string).await()
        if (dataList.intialDataResult < 1) {
            return@withContext ResultState.Failure("Reason of error...")
        } else {
            database.myDataBase.insertAll(dataList)
            return@withContext ResultState.Success
        }
    }
}

Now, report result to UI

fun onSearchButtonClicked(input: String) {
    coroutineScope.launch {
        val resultState = repo.insertToDatabase(input)
        stateLiveData.value = resultState
    }
}

In UI,

viewModel.stateLiveData.observe(viewLifeCycleOwner, Observer { state ->

    when (state) {
        is ResultState.Success -> { /* show success in UI */ }
        is ResultState.Failure -> { /* show error in UI with state.message variable */ }
    }
})

Similarly, you can add a ResultState.PROGRESS to show that a task is running in the UI.

If you have any queries, please add a comment.

Upvotes: 3

Related Questions