在上一次 Google I/O 大会上,Jose Alcerreca 和 Yigit Boyar告诉我们,我们不应再使用 LiveData 来获取数据。现在我们应该使用挂起函数进行一次性提取并使用 Kotlin 的 Flow 创建数据流。我同意协程非常适合一次性获取或其他 CRUD 操作,例如插入等。但是在我需要数据流的情况下,我不明白 Flow 给我带来了什么优势。在我看来,LiveData 也在做同样的事情。
流程示例:
视图模型
val items = repository.fetchItems().asLiveData()
Run Code Online (Sandbox Code Playgroud)
存储库
fun fetchItems() = itemDao.getItems()
Run Code Online (Sandbox Code Playgroud)
道
@Query("SELECT * FROM item")
fun getItems(): Flow<List<Item>>
Run Code Online (Sandbox Code Playgroud)
LiveData 示例:
视图模型
val items = repository.fetchItems()
Run Code Online (Sandbox Code Playgroud)
存储库
fun fetchItems() = itemDao.getItems()
Run Code Online (Sandbox Code Playgroud)
道
@Query("SELECT * FROM item")
fun getItems(): LiveData<List<Item>>
Run Code Online (Sandbox Code Playgroud)
我还想看到一些使用协程和 Flow 来处理 Room 或 Retrofit 的项目示例。我只找到了一个 Google 的ToDo 示例,其中协程用于一次性获取,然后在更改时手动重新获取数据。
android kotlin android-livedata kotlin-coroutines kotlinx.coroutines.flow
我想从资产文件夹中的json文件中预填充我的Room数据库。我遵循Google Sunflower示例。我复制了SeedDatabaseWorker类:
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.dmitrysimakov.gymlab.data.GymLabDb
import com.dmitrysimakov.gymlab.data.entity.Training
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import javax.inject.Inject
class SeedDatabaseWorker(val context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
private val TAG = SeedDatabaseWorker::class.java.simpleName
@Inject lateinit var database: GymLabDb
override fun doWork(): Worker.Result {
val plantType = object : TypeToken<List<Training>>() {}.type
var jsonReader: JsonReader? = null
return try {
val inputStream = context.assets.open("training.json")
jsonReader = JsonReader(inputStream.reader())
val plantList: List<Training> = Gson().fromJson(jsonReader, plantType)
database.trainingDao().insert(plantList)
Worker.Result.SUCCESS
} …Run Code Online (Sandbox Code Playgroud) android dagger-2 android-room android-architecture-components android-workmanager
现在我有这个代码:
class MyFragment : DaggerFragment() {
...
private fun setTimePickerDialog() {
binding.timeButton.setOnClickListener{
val calendar = viewModel.calendar
val curHourOfDay = calendar.get(Calendar.HOUR_OF_DAY)
val curMinute = calendar.get(Calendar.MINUTE)
val dialog = TimePickerDialog(context, { _, hourOfDay, minute ->
val c = Calendar.getInstance()
c.set(1970, 0, 1, hourOfDay, minute)
viewModel.time.value = SimpleDateFormat("HH:mm:ss").format(c.time)
}, curHourOfDay, curMinute, true)
dialog.show()
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
我想利用 DataBinding 库而不是setOnClickListener在我的片段中写入。但我无法将此代码移至ViewModel,因为需要上下文。通过使用 DataBinding 和 MVVM 单击按钮来显示 DatePickerDialog 的简洁方法是什么?
android mvvm android-databinding android-architecture-components
每次启动应用程序时都会出现错误。
E/SQLiteLog: (283) recovered 22 frames from WAL file /data/data/com.dmitrysimakov.kilogram/databases/androidx.work.workdb-wal
Run Code Online (Sandbox Code Playgroud)
该应用程序工作正常,但我想知道为什么会出现此错误。database/androidx.work.workdb-wal 它是 Worker 的日志。我使用 Worker 来预填充我的数据库。
Room.databaseBuilder(app, KilogramDb::class.java, "kilogram.db")
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build()
WorkManager.getInstance().enqueue(request)
}
})
.fallbackToDestructiveMigration()
.build()
Run Code Online (Sandbox Code Playgroud) android android-sqlite android-architecture-components android-workmanager