Home > Net >  Screen not recomposing when state value changes - Jetpack Compose
Screen not recomposing when state value changes - Jetpack Compose

Time:11-01

It is a video call screen . It needs token and channel name to work which needs to be passed to init call engine. I am storing these in a data class which is used as a mutable state.

Screen State Data class

@Keep
data class CallScreenState(
    val callerId: Int? = null,
    val recieverId: Int? = null,
    val chatRoom: ChatRoom.Data? = null,
    val rtcToken: AgoraTokenResponse.TokenData? = null
)

And in viewmodel initializing state by this code :

var callScreenState by mutableStateOf(CallScreenState())

and in viewmodel on success response of chat room and token api the state is updated with this code.

callScreenState = callScreenState.copy(
                                chatRoom = chatRoom.data,//from response
                                rtcToken = token.data   //from response
                            )

From here it is expected to recompose the screen with new updated value of chatRoom and rtcToken.

And in composable

val screenState = remember {
    viewModel.callScreenState
}

this screen state is used to pass values to the init engine

val mEngine = remember {
    initEngine(
        context,
        object : IRtcEngineEventHandler() {
            override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
                Timber.e("hhp-CallScreen onJoinChannelSuccess channel:$channel,uid:$uid,elapsed:$elapsed")
            }

            override fun onUserJoined(uid: Int, elapsed: Int) {
                Timber.e("hhp-CallScreen onUserJoined:$uid")
                val desiredUserList = remoteUserMap.toMutableMap()
                desiredUserList[uid] = null
                remoteUserMap = desiredUserList.toMap() as HashMap<Int, TextureView?>
            }

            override fun onUserOffline(uid: Int, reason: Int) {
                Timber.e("hhp-CallScreen onUserOffline:$uid")
                val desiredUserList = remoteUserMap.toMutableMap()
                desiredUserList.remove(uid)
                remoteUserMap = desiredUserList.toMap() as HashMap<Int, TextureView?>
            }

            override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
                Timber.e("hhp-CallScreen onNetworkQuality $uid $txQuality $rxQuality")

            }
        },
        screenState.chatRoom?.channelName ?: "",  //Not recomposing when value changes in viewmodel
        viewModel.userRole,
        token = screenState.rtcToken?.token ?: "" //Not recomposing when value changes in viewmodel
    )
}

This is the initEngine function creation

fun initEngine(
    current: Context,
    eventHandler: IRtcEngineEventHandler,
    channelName: String,
    userRole: String,
    token: String
): RtcEngine =
    RtcEngine.create(current, BuildConfig.AGORA_APPID, eventHandler).apply {
        enableVideo()
        setChannelProfile(1)
        if (userRole == "Broadcaster") {
            setClientRole(1)
        } else {
            setClientRole(0)
        }
        //Expected to be recomposed when screen state value updated with new values
        joinChannel(token, channelName, "", 0)
    }

I understand at the very beginging, channel name and token inside the screen state is empty that is before the api call . Once api for getting token and chat room gives succes , the screen state updated from viewmodel and i expect the initEngine fun to be called again as it should recompose. But it is not. Am I Missing something ? How to make it recompose whenver the channelname value inside screen sctate changes?

CodePudding user response:

I can't understand your entire use-case but have you tried specifying a key to your remember?

How to make it recompose whenver the channelname value inside screen sctate changes?

You can try either of these, though I'm not sure if they would solve your problem, but when you supply a key to remember and it changes, it will re-calculate, assuming the channelName that has been calculated by remember previously will be different on the next pass.

This,

val screenState = remember(key1 = channelname) {
    viewModel.callScreenState
}

or this

val mEngine = remember(key1 = channelname) { ... }
  • Related