十、使用Jetpack Compsoe编写一个写小说的Android应用:使用Flow让列表状态实时更新

在完成了一套viewmodel的代码后,相信后续的大家也能照猫画虎的写出来了,但是现在又产生了新的问题,我要如何将数据库中的数据实时显示在列表中呢?

这时候就要用到Flow这个东西了,或者LiveData都行,这里就用Flow了。

然后还要做一下区分:

创建小说是在FictionNamePage中,但是显示列表是在MainPage中,所以我们要先给MainPage也来一套viewmodel,然后再考虑它的列表显示问题。

1、MainPageViewModel建立

1.1创建MainPageDao 接口

直接上代码

@Dao
interface MainPageDao {
    @Delete
    suspend fun deleteBook(book: Book)

    //获取所有书列表,用于列表显示
    @Query("SELECT * FROM fictionData ORDER BY fiction_id DESC")
    fun getAllBooks(): Flow<List<Book>>

    //获取一本书的id号,用于后续删除
    @Query("SELECT * FROM fictionData WHERE fiction_id = :idF")
    suspend fun getBookOfId(idF: Int): Book?

}

这里可以看到第二条代码,就是以Flow的形式声明的,之后我们要通过它来实时刷新我们的列表。

1.2AppDatabase中声明

这里只需要加一句话

abstract fun mainPageDao(): MainPageDao

1.3新建接口MainPageRepository 

interface MainPageRepository {

    suspend fun deleteBook(book: Book)

    //获取所有书列表,用于列表显示
    fun getAllBooks(): Flow<List<Book>>

    //获取一本书的id号,用于后续删除
    suspend fun getBookOfId(idF: Int): Book?

}

这个和上篇一样,没啥好说的。

1.4新建类OfflineMainPageRepository

class OfflineMainPageRepository(private val mainPageDao: MainPageDao) : MainPageRepository {

    override suspend fun deleteBook(book: Book) = mainPageDao.deleteBook(book)

    //获取所有书列表,用于列表显示
    override fun getAllBooks(): Flow<List<Book>> = mainPageDao.getAllBooks()

    //获取一本书的id号,用于后续删除
    override suspend fun getBookOfId(idF: Int): Book? = mainPageDao.getBookOfId(idF)

}

用来将两个接口接起来的函数。

1.5新建MainPageViewModel

class MainPageViewModel(private val mainPageRepository: MainPageRepository) : ViewModel() {


    //用于列表显示
    fun getAllBooks(): Flow<List<Book>> {
        return mainPageRepository.getAllBooks()
    }

    //删除某一本书,或者某一章节
    fun deleteBookAndAll(id:Int){
        viewModelScope.launch {
            val deleteBook = mainPageRepository.getBookOfId(id)
            mainPageRepository.deleteBook(deleteBook!!)
        }
    }


}

可以看到有关Flow的函数返回值一直是Flow类型的。

1.6在AppDataContainer中添加mainPageRepository

interface AppContainer {
    val mainPageRepository: MainPageRepository
    val fictionNameRepository: FictionNameRepository
}

/**
 * [AppContainer] implementation that provides instance of [OfflineItemsRepository]
 */
class AppDataContainer(private val context: Context) : AppContainer {
    /**
     * Implementation for [ItemsRepository]
     */
    override val mainPageRepository: MainPageRepository by lazy {
        OfflineMainPageRepository(AppDatabase.getInstance(context).mainPageDao())
    }

    override val fictionNameRepository: FictionNameRepository by lazy {
        OfflineFictionNameRepository(AppDatabase.getInstance(context).fictionNameDao())
    }
}

完全按照上一篇做而已。

1.7在AppViewModelProvider中初始化MainPageViewModel

object AppViewModelProvider {
    val Factory = viewModelFactory {
        initializer {
            MainPageViewModel(
                fictionApplication().container.mainPageRepository
            )
        }
        initializer {
            FictionNameViewModel(fictionApplication().container.fictionNameRepository)
        }

    }
}

到这里为止基本上ViewModel就写好了,接下来到页面中去写实现方法。

2、Flow的使用

2.1首先要在MainPage中添加ViewModel

fun MainPage(navController: NavController,
             viewModel: MainPageViewModel = viewModel(factory = AppViewModelProvider.Factory)
)

2.2声明remember类型的参数来保存数据

val book = remember {
        mutableListOf<Book>()
    }

这里我声明了一个Book类型的可变List,然后remember字段就是为了全局保存,以防横竖屏切换之类的动作导致获取的数据丢失。

2.3调用Flow类型的函数

val books = viewModel.getAllBooks().collectAsState(initial = book).value

首先,我们在最开始的Dao中写的getAllBooks函数是一个非主线程函数,他不能在主线程里运行,因此就要用到collectAsState字段将获取到的 Flow<List<Book>>值转换为 State<List<Book>>

而State想要获取其中的值,就可以用.value方法来获取。

此时的books就是List<Book>类型,这不就和我们之前随便新建的data的类型一致了吗?所以将books这个变量写到lazycolumn的items处就行了!

2.4列表实时刷新

这个时候,我们获取的每个it都是一个Book类型的数据类。我们只需在Text中使用it.的方式就能获取其中定义好的参数。

这时,我们的列表实时刷新就完成了,测试一下!

注意:

经过多次测试发现这是因为点击加号后跳转到新页面,在新页面操作完成后再跳转回旧页面的时候,自动触发了Compose,如果是在当前页面进行实时操作,那么列表将不会实时刷新。 

  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HO灵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值