Home > Enterprise >  Observer is called twice at the same time in Kotlin
Observer is called twice at the same time in Kotlin

Time:08-16

When the button is clicked, data is received from the API, after which the Observer is fired, however, even with removeObservers, it is called twice. Without removeObservers it triggers more than 2 times.

MainActivity

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContent {
        TestApiAppTheme {
            Surface() {
                TextInfo()
            }
        }
    }
}

@Preview
@Composable
fun TextInfo() {

    val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)

    var txt = remember {
        mutableStateOf(0)
    }

    viewModel.serverInfoResponse.removeObservers(this)
    viewModel.serverInfoResponse.observe(this) {
        txt.value = it.players
        Toast.makeText(this, "${it.players} -", Toast.LENGTH_SHORT).show()
    }

    Column() {
        Text(
            text = txt.value.toString(),
        )

        Button(onClick = {
            viewModel.getServerInfo()
            visible = true
        }) {
            Text("Update")
        }
    }
}}

ViewModel

var serverInfoResponse = MutableLiveData<ServerInfo>()

fun getServerInfo() {
    viewModelScope.launch {
        val apiService = ApiService.getInstance()

        val info = apiService.getInfo()
        serverInfoResponse.value = info
    }
}

CodePudding user response:

Composable functions can get called many times although the compiler tries to reduce how often.

You should not have side effects in them such as adding and removing the observer. Since LiveData sends the last item out to new subscribers, every time this function composes you get the value again.

The correct way to consume live data is to convert it to a state. https://developer.android.com/reference/kotlin/androidx/compose/runtime/livedata/package-summary

But then you still have problems with showing the toast too often. For that you will need something like a LaunchEffect to make sure you only show a toast once. Might want to consider if you really need a toast or if a compose type UI would be better.

CodePudding user response:

A composable function can be called multiple times, whenever the it observes changes removeObserver() and observe() should not be called directly but, rather in some effect.

The extension function observeAsState() does all work to subscribe and correctly unsubscribe for you.

  • Related