我正在使用架构组件学习 Android 开发。我对它们的正确使用有一些疑问。 这是我的代码,它是在本地保存数据的简单应用程序。
产品实体
@Entity
data class ProductEntity (
@PrimaryKey(autoGenerate = true)
val id: Int,
val name:String,
)
产品DAO
@Dao
interface ProductDAO {
@Insert
suspend fun insert(productEntity: ProductEntity)
@Query("SELECT * FROM productentity ORDER BY name")
fun getAll(): LiveData<List<ProductEntity>>
@Query("SELECT * FROM productEntity WHERE id=:id")
fun getProductById(id: Int): LiveData<ProductEntity>
}
产品存储库
class ProductRepository (private val productDAO: ProductDAO) {
suspend fun insert(product: ProductEntity){
contatoDAO.insert(product)
}
fun getAll(): LiveData<List<ProductEntity>> {
return productDAO.getAll()
}
fun getProductById(id: Int): LiveData<ProductEntity>{
return productDAO.getProductById(id)
}
}
产品视图模型
class ProductViewModel(private val repository: ProductRepository) : ViewModel(){
val allProducts:LiveData<List<ProductEntity>> = repository.getAll()
lateinit var product : LiveData<ProductEntity>
fun insert(productEntity: ProductEntity) = viewModelScope.launch(Dispatchers.IO){
repository.insert(productEntity)
}
fun getProductById(id: Int) {
viewModelScope.launch {
product = repository.getProductById(id)
}
}
companion object {
fun productViewModelFactory() : ViewModelProvider.Factory =
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
val application = checkNotNull(
extras[APPLICATION_KEY]
)
return ProductViewModel(
(application as Application).repository
) as T
}
}
}
}
最后,在我的片段中:
class MyFragment : Fragment() {
lateinit var product: ProductEntity
val viewModel : ProductViewModel by viewModels { ProductViewModel.productViewModelFactory() }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.allProducts.observe(viewLifecycleOwner) { list ->
list?.let {
myAdapter.updateList(list)
}
}
val p = ProductEntity(1,'Smartphone')
viewmodel.insert(p)
viewModel.getProductById(1)
viewModel.product.observe(viewLifecycleOwner) { result ->
result?.let {
product = result
}
}
viewModel.delete(product)
}
}
问题:
在仅管理本地数据的应用程序中使用 LiveData 有意义吗? (参见 ProductDAO)
假设问题1的答案是“是”,即使是有趣的 getProductById(id: Int): LiveData 也应该返回一个 LiveData 吗?
Android 网站表示 LiveData 对象不应在存储库中使用(参见此处)。但是,我在许多示例存储库中使用 LiveData,作为我自己的代码(ProductRepository)
使用 LiveData 还是 Flow 更好?
在我的片段中,当我尝试使用 viewModel.delete(product) 删除产品(通过观察者检索)时,应用程序崩溃。错误消息显示“NullPointerException:指定为非 null 的参数在 ProductRepository.getProductById 中为 null”。为什么会这样?我猜想观察者仍然存在,然后使用该 ID 查询数据库会返回 null,因为该对象不再存在。但我不知道如何解决它。有什么帮助吗?
谢谢!
1- 不要在 Dao 中使用 LiveData。仅退回您的产品。无需更多……也许流动;流已经使用协程。支持异步流...
2-
3-LiveData 旨在根据 UI 组件的生命周期更新它们。另一方面,存储库通常独立于 UI 组件运行,并且通常具有较长的生命周期。将 LiveData 存储在存储库中可能会导致生命周期管理问题。
4- Flow 在某个地方更好,livedata 在某个地方更好...对我来说,Livedata 的 Flow 好一点:)
5-等待结果...你可以像这样修复它。
viewModel.product.observe(viewLifecycleOwner) { result ->
result?.let {
product = result
viewModel.delete(product)
}
}
花时间观察。如果你不想崩溃,你会检查产品是否为空。
if(product != null) {
viewModel.delete(product)
}
或
@PrimaryKey(autoGenerate = true)
val id: Int,
Id 是自动生成的!首次打开的 App id 1 被创建并删除。再次打开应用程序;产品采用新 ID。 2、3、4...
val p = ProductEntity(1,'Smartphone')
1 为无效元素。