Экран не перекомпоновывается при изменении значения состояния — Jetpack Compose

Это экран видеовызова. Для работы ему нужен токен и имя канала, которые необходимо передать механизму вызова инициализации. Я храню их в классе данных, который используется как изменяемое состояние.

Класс данных состояния экрана

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

И в состоянии инициализации viewmodel по этому коду:

var callScreenState by mutableStateOf(CallScreenState())

и в модели просмотра при успешном ответе чата и API токена состояние обновляется с помощью этого кода.

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

Отсюда ожидается перекомпоновка экрана с новым обновленным значением chatRoom и rtcToken.

И в компоновке

val screenState = remember {
    viewModel.callScreenState
}

это состояние экрана используется для передачи значений механизму инициализации

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
    )
}

Это создание функции initEngine

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)
    }

Я так понимаю в самом начале имя канала и токен внутри состояния экрана пусты то есть до вызова апи. Как только API для получения токена и чата дает успех, состояние экрана обновляется из модели представления, и я ожидаю, что удовольствие initEngine будет вызвано снова, поскольку оно должно перекомпоновываться. Но это не так. Я что-то упускаю ? Как заставить его перекомпоновываться при изменении значения имени канала внутри экрана?

4
0
308
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не могу понять весь ваш вариант использования, но вы пытались указать key на свой remember?

Как заставить его перекомпоновываться, когда значение имени канала находится внутри экрана изменения?

Вы можете попробовать любой из них, хотя я не уверен, решат ли они вашу проблему, но когда вы вводите key в remember и он изменяется, он будет re-calculate, предполагая, что channelName, который использовался в предыдущем расчете remember's, будет другим на следующий re-composition.

Этот,

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

или это

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

Идеально! Это решило проблему, у меня не было ключа внутри. Большое спасибо @z.y

Harish Padmanabh 01.11.2022 12:12

Другие вопросы по теме