kotlin 带有房间数据库的通用 Package 器

szqfcxe2  于 2023-03-13  发布在  Kotlin
关注(0)|答案(2)|浏览(113)

我想实现我的room database中的generic wrapper。我自己实现的那个,好像没有用到它。你能帮我一下吗?首先,这里有一些代码:

** Package 器**

sealed class MyState{
data class Success<out T>(val data: T) : DatabaseState()
data class Error<out T>(val error: T) : DatabaseState()
}

存储库

val myCurr: Flow<MyModelClass> =
    mydao.getCurr().shareIn(
        scope, replay = 1, started = SharingStarted.WhileSubscribed()
    )

视图模型

private val _myState: MutableSharedFlow<MyState<myModel>> = MutableSharedFlow(replay = 1)
val stateGetter: SharedFlow<MyState<myModel>> get() = _myState
    

    fun myFun() {
    viewModelScope.launch(Dispatchers.IO ) {
        myRepository.myCurr
            .catch { _myState.emit(MyState.Error(it.cause))
            .collect { myModel->
                _myState.emit(DatabaseState.Success(myModel.curr))
            }
    }
}

这对我来说还是一个新东西,所以代码可能不是最好的。我只是想知道,如果我的Repository类是正确的。我读到一些地方(可能在文档中),我不应该使用函数从db中获取值,而应该使用val。有没有办法使用shareIn,并将其存储在泛型 Package 器中?这是一个好方法吗?

fcwjkofz

fcwjkofz1#

我看不出使用函数从数据库中获取值有什么问题,请检查以下代码,作为存储库和视图模型交互的示例:

class BooksRepositoryImpl @Inject constructor(
 private val libraryDatabase: LibraryDatabase) : BooksRepository {

override suspend fun insertBook(bookDomainEntity: BookDomainEntity): Either<Error, Success> {
    return try {
        Right(libraryDatabase.insertBookIntoLibrary(bookDomainEntity))
    } catch (ex: Exception) {
        Left(DatabaseError)
    }
}

如果你想缓存一些数据,你可以在存储库中添加一个瓦尔属性,当然这不是强制性的,你仍然可以调用一个数据库来获取你的数据。
下面你可以看到我如何在我的代码中调用这个方法:

fun insertBookIntoLibrary(bookEntity: BookDomainEntity) = flow {
    val libraryState = withContext(coroutineDispatcher) { repository.insertBook(Params(bookEntity)) }
    emit(libraryState.fold(
            ::handleError,
            ::handleSuccess))
    }.stateIn(
            scope = viewModelScope,
            started = SharingStarted.Lazily,
            initialValue = Loading)
wkyowqbh

wkyowqbh2#

val属性适用于不需要输入的流。当需要检索基于特定输入的流时,函数是必需的,正如@LuisPascual的答案所示。但是,创建SharedFlow并在函数中返回它是没有意义的,因为这样每个函数调用者将获得不同的SharedFlow示例(没有任何内容将被共享)。
因此,您的存储库代码是完美的,但是您的ViewModel代码存在一些问题。
1.你有一个函数必须被调用才能使你的SharedFlow工作。这是毫无意义的卷积。为什么不直接在init块中完成这项工作,这样它就会自动发生,而不必记住在某处调用myFun,但要非常小心,不要调用myFun超过一次?如果一个外部类,如Activity在创建时调用它,将很难防止它被调用一次以上。
1.更简单的方法是使用shareIn,这样就不需要在init块中执行上述操作,也不需要一个单独的支持MutableSharedFlow属性。
1.你不需要指定一个调度器来调用房间里的流!实际上,你唯一应该使用flowOn操作符的时候是在flow { }构建器之后的一系列调用中(或类似的)调用或执行阻塞工作的X1 M8 N1 X运算符,因为你从另一个类得到的任何流应该已经在内部适当地委托了它自己(遵循关注点分离和封装的原则)Room DAO永远不会返回一个脆弱的Flow,它需要一些特定的Dispatcher来避免阻塞线程。
因此,以上所有ViewModel代码都应替换为:

val stateGetter: SharedFlow<MyState<myModel>> =
    myRepository.myCurr
        .map { DatabaseState.Success(myModel.curr) }
        .catch { _myState.emit(MyState.Error(it.cause))
        .shareIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), replay = 1)

另外,我不确定您是否打算让您的流在存储库和ViewModel中都成为共享流。

相关问题