android 如何在重新创建片段/活动时忽略liveData的最后一个值?

drkbr07n  于 2022-11-03  发布在  Android
关注(0)|答案(2)|浏览(174)

在一个特殊的例子中,我遇到了liveData的问题。当http服务的响应代码为Code = 2时,这意味着会话令牌已经过期。在这种情况下,我导航到LoginFragment以再次登录用户。如果用户登录,我将返回到之前的片段,当我开始在onViewCreated函数中观察liveData时,它会给我它的最后一个值,即:代码= 2,因此应用程序导航回登录名,这是错误的。

  • 我有一个密封职业 *
sealed class Resource<T>(
    var data: T? = null,
    val message: String? = null,
    val Code: Int? = null

) {
    class Success<T>(data: T?) : Resource<T>(data)
    class Error<T>(message: String, code: Int? = null) : Resource<T>(message = message, Code = code)
    class Loading<T> : Resource<T>()
}
  • 这是ViewModel上的代码:*
val mLiveData: MutableLiveData<Resource<Data>> = MutableLiveData()

fun getData() {
    viewModelScope.launch {
        mLiveData.postValue(Resource.Loading())
        try {
            if (app.hasInternetConnection()) {
                // get Data From API
                val response = repository.getData()
                if(response.isSuccessful){
                    mLiveData.postValue(Resource.Success(parseSuccessResponse(response.body())))
                } else {
                    mLiveData.postValue(Resource.Error(parseErrorResponse(response.body())))
                }
            } else {
                mLiveData.postValue(Resource.Error("Connection Fail"))
            }
        } catch (t: Throwable) {
            when (t) {
                is IOException -> mLiveData.postValue(Resource.Error("Connection Fail"))
                else -> mLiveData.postValue(Resource.Error("Convertion Fail"))
            }
        }
    }
}
  • 这是片段上的代码,observeForData()onViewCreated函数中调用:*
private fun observeForData() {
    mLiveData.getData.observe(viewLifecycleOwner, Observer { response ->
        when (response) {
            is Resource.Success -> {
                isLoading = false
                updateUI(response.data)
            }
            is Resource.Error -> {
                isLoading = false
                if (response.Code == 2) {
                    // Token Expired
                    navigateToLogin()
                } else {
                    showErrorMessage(response.message)
                }
            }
            is Resource.Loading -> {
                isLoading = true
            }
        }
    })
}

如何解决这个问题?当导航到LoginFragment时,如果片段被破坏,是否有方法从liveData中删除最后一个值或状态?

  • 谢谢-谢谢
gab6jxml

gab6jxml1#

一个经常被推荐的解决方案是SingleLiveEvent,它是一个简单的类,可以通过复制粘贴到项目中。
对于一个框架解决方案,我建议使用SharedFlow。一些Android开发人员建议无论如何都要从LiveData切换到Flows,以便更好地将数据与视图分离。如果您为SharedFlow指定一个重放值0,则观察它的新Activity和Fragments将不会获得以前的值,而只会获得新发布的值。
未经测试的示例ViewModel代码:

val dataFlow: Flow<Resource<Data>> = MutableSharedFlow(replay = 0)

init {
    viewModelScope.launch {
        // Same as your code, but replace mLiveData.postValue with dataFlow.emit
    }
}

在片段中:

private fun observeForData() {
    isLoading = true
    lifecycleScope.launch {
        mLiveData.dataFlow
            .flowWithLifecycle(this, Lifecycle.State.STARTED)
            .collect { onDataResourceUpdate(it) }
    }
}

// (Broken out into function to reduce nesting)
private fun onDataResourceUpdate(resource: Resource): Unit = when(resource) {
    is Resource.Success -> {
        isLoading = false
        updateUI(response.data)
    }
    is Resource.Error -> {
        isLoading = false
        if (response.Code == 2) {
            // Token Expired
            navigateToLogin()
        } else {
            showErrorMessage(response.message)
        }
    }
    is Resource.Loading -> isLoading = true
}
3pmvbmvn

3pmvbmvn2#

要更改实时数据的上次更新值,您可以在onDestroy()时使用默认空值设置“Resource”类。

onDestroy(){
//in java ,it will be new Resource instance
Resource resourceWithNull=new Resource();

mLiveData.setValue(resourceWithNull);
}

当您重新启动片段时,实时数据将发出具有空值的资源作为响应。
然后,您可以使用in observer编写代码

if(response.data!=null)
{
//your code

}

相关问题