Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/180.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android,MVI模式+;科特林流量+;房间+;改装,如何将它们装配在一起?_Android_Android Fragments_Mvvm_Android Room_Flow - Fatal编程技术网

Android,MVI模式+;科特林流量+;房间+;改装,如何将它们装配在一起?

Android,MVI模式+;科特林流量+;房间+;改装,如何将它们装配在一起?,android,android-fragments,mvvm,android-room,flow,Android,Android Fragments,Mvvm,Android Room,Flow,我是MVI模式的新手。所以我试图理解如何将所有的部分组合在一起。 我有一个应用程序,我使用MVI模式构建(或者至少这是我的本意)。我有我的片段(我使用了导航组件,但目前只关注一个片段),它由自己的ViewModel支持。然后我有一个repository类,其中所有viewmodels都检索数据。存储库有两个数据源,一个web API和一个用作数据缓存的本地DB,我使用了用于DB管理的空间。 我尝试了不同的方法来解决这个问题。目前,我是这样做的: 在DAO中,我使用此指令从数据库检索数据: @Qu

我是MVI模式的新手。所以我试图理解如何将所有的部分组合在一起。 我有一个应用程序,我使用MVI模式构建(或者至少这是我的本意)。我有我的片段(我使用了导航组件,但目前只关注一个片段),它由自己的ViewModel支持。然后我有一个repository类,其中所有viewmodels都检索数据。存储库有两个数据源,一个web API和一个用作数据缓存的本地DB,我使用了用于DB管理的空间。 我尝试了不同的方法来解决这个问题。目前,我是这样做的: 在DAO中,我使用此指令从数据库检索数据:

@Query("SELECT * FROM Users WHERE idTool=:idTool AND nickname LIKE '%' || :query || '%'")
fun users(idTool: Int, query: String) : Flow<List<User>>
在ViewModel中,我创建了两个由中介LiveData协调的可变LiveData:

val nicknameQuery = MutableStateFlow("")
private val nicknameQueryFlow = nicknameQuery.flatMapLatest {
    repository.usersFlow(idToolQuery.value, it)
}
val idToolQuery = MutableStateFlow(DEFAULT_TOOL_ID)
private val idToolQueryFlow = idToolQuery.flatMapLatest {
    repository.usersFlow(it, nicknameQuery.value)
}

val users = MediatorLiveData<List<User>>()

init {
    users.addSource(nicknameQueryFlow.asLiveData()) {
        users.value = it
    }
    users.addSource(idToolQueryFlow.asLiveData()) {
        users.value = it
    }

    fetchUsers()
}
如果已经有使用此特定idTool的缓存用户,则此方法将检查数据库,如果没有,则从web获取用户,并将检索到的数据存储到数据库中。这是我的存储库类中的方法:

suspend fun fetchUsers(
    idTool: Int,
    forceRefetch: Boolean = false
): Flow<DataState<List<User>>> = flow {

    try {
        var cachedUser = userDao.users(idTool, "").first()
        val users: List<User>

        if(cachedUser.isEmpty() || forceRefetch) {
            Log.d(TAG, "Retrieve users: from web")
            emit(DataState.Loading)

            withContext(Dispatchers.IO) {
                appJustOpen = false
                val networkUsers =
                    api.getUsers(
                        idTool,
                        "Bearer ${sessionClient.tokens.accessToken.toString()}"
                    )
                users = entityMapper.mapFromEntitiesList(networkUsers)

                userDao.insertList(users)
            }
        } else {
            users = cachedUser
        }

        emit(DataState.Success(users))
    } catch (ex: Exception) {
        emit(DataState.Error(ex))
    }
}
最后,在我的片段中,我有:

userListViewModel.dataState.observe(viewLifecycleOwner, { dataState ->
            when (dataState) {
                is DataState.Success -> {
                    showUserList()
                }
                is DataState.Error -> {
                    Log.e("TEST", dataState.exception.toString())
                    hideLoader()
                    Toast.makeText(activity, "Error retrieving data: ${dataState.exception}", Toast.LENGTH_LONG).show()
                }
                is DataState.Loading -> {
                    showLoader()
                }
                else -> {
                    // Do Nothing in any other case
                }
            }
        })
此时,Success state获取了一个用户列表,但该列表来自于以前的方法,此时它是无用的,因为在获取数据后,列表被插入到数据库中,我有一个到数据库的流,它负责更新UI。这样,当我更改idTool、更改查询、删除用户时,视图总是会得到通知 这种方法正确吗

在此之前,我使用了另一种方法。我返回的不是来自数据库的流,而是一个列表。然后我的fetchUsers总是返回一个DataState,它在DB中进行检查,如果没有找到任何东西,它就会从web上获取数据并返回该列表。这种方法给我带来了一些问题,因为每次我更改idTool或query时,都必须调用fetchUsers方法。即使从数据库中删除了用户,视图也不会得到通知,因为我并没有和数据库直接通信

suspend fun fetchUsers(
    idTool: Int,
    forceRefetch: Boolean = false
): Flow<DataState<List<User>>> = flow {

    try {
        var cachedUser = userDao.users(idTool, "").first()
        val users: List<User>

        if(cachedUser.isEmpty() || forceRefetch) {
            Log.d(TAG, "Retrieve users: from web")
            emit(DataState.Loading)

            withContext(Dispatchers.IO) {
                appJustOpen = false
                val networkUsers =
                    api.getUsers(
                        idTool,
                        "Bearer ${sessionClient.tokens.accessToken.toString()}"
                    )
                users = entityMapper.mapFromEntitiesList(networkUsers)

                userDao.insertList(users)
            }
        } else {
            users = cachedUser
        }

        emit(DataState.Success(users))
    } catch (ex: Exception) {
        emit(DataState.Error(ex))
    }
}
private val _dataState = MutableLiveData<DataState<List<User>>>()
val dataState: LiveData<DataState<List<User>>> get() = _dataState
private fun fetchUsers() {
    viewModelScope.launch {
        repository.fetchUsers(DEFAULT_TOOL_ID).collect {
            _dataState.value = it
        }
    }
}
userListViewModel.dataState.observe(viewLifecycleOwner, { dataState ->
            when (dataState) {
                is DataState.Success -> {
                    showUserList()
                }
                is DataState.Error -> {
                    Log.e("TEST", dataState.exception.toString())
                    hideLoader()
                    Toast.makeText(activity, "Error retrieving data: ${dataState.exception}", Toast.LENGTH_LONG).show()
                }
                is DataState.Loading -> {
                    showLoader()
                }
                else -> {
                    // Do Nothing in any other case
                }
            }
        })