十、使用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>

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

}

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

1.2AppDatabase中声明

这里只需要加一句话

abstract fun mainPageDao(): MainPageDao

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

1.3新建接口MainPageRepository 

interface MainPageRepository {

    suspend fun deleteBook(book: Book)

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

    //获取一本书的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> = 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> {
        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类型的可变List,然后remember字段就是为了全局保存,以防横竖屏切换之类的动作导致获取的数据丢失。

2.3调用Flow类型的函数

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

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

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

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

2.4列表实时刷新

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

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

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

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

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

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

注意:

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

你可能感兴趣的:(Android,android,kotlin,android,jetpack)