情况非常简单。我有一个简单的 android 应用程序,通过底部导航栏显示 4 个片段,以及一个中央 Room 数据库。每个片段都应该能够通过视图模型对数据库执行 CRUD 操作(细节可能无关紧要,但我也会展示这一点以确保):
class ViewModel(application: Application): AndroidViewModel(application) {
val readAllIngredients: LiveData<List<Ingredient>>
val readAllRecipes: LiveData<List<Recipe>>
private val ingredientRepository: IngredientRepository
private val recipeRepository: RecipeRepository
init {
val ingredientDAO = ShoppingAppDatabase.getDatabase(application).ingredientDAO()
val recipeDAO = ShoppingAppDatabase.getDatabase(application).recipeDAO()
ingredientRepository = IngredientRepository(ingredientDAO)
recipeRepository = RecipeRepository(recipeDAO)
readAllIngredients = ingredientRepository.allIngredients
readAllRecipes = recipeRepository.allRecipes
}
fun addIngredient(ingredient: Ingredient) {
viewModelScope.launch(Dispatchers.IO) {
ingredientRepository.put(ingredient)
}
}
fun deleteIngredient(ingredient: Ingredient) {
viewModelScope.launch(Dispatchers.IO) {
ingredientRepository.delete(ingredient)
}
}
fun addRecipe(recipe: Recipe) {
viewModelScope.launch(Dispatchers.IO) {
recipeRepository.put(recipe)
}
}
fun updateRecipe(recipe: Recipe) {
viewModelScope.launch(Dispatchers.IO) {
recipeRepository.update(recipe)
}
}
fun updateIngredient(ingredient: Ingredient) {
viewModelScope.launch(Dispatchers.IO) {
ingredientRepository.update(ingredient)
}
}
}
我正在每个片段中初始化一个视图模型,但成功率有限。这是一个一切正常的片段:
class InventoryFragment() : Fragment() {
private var listAdapter = IngredientAdapter()
private lateinit var viewModel : ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_inventory, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
listAdapter = IngredientAdapter()
recycler_view.apply {
layoutManager = LinearLayoutManager(activity)
adapter = listAdapter
}
viewModel = ViewModelProvider(this).get(ViewModel::class.java)
viewModel.readAllIngredients.observe(viewLifecycleOwner, Observer { ingredient -> listAdapter.setData(ingredient) })
add_button.setOnClickListener{
val errorMessages = validateInput()
if(errorMessages.isNotEmpty()) {
displayToast(activity, errorMessages)
}
else {
viewModel.addIngredient(Ingredient(
edit_name.text.toString(),
edit_qty.text.toString().toFloat(),
edit_um.text.toString()
))
listAdapter.notifyDataSetChanged()
displayToast(activity, "Ingredient added")
hideKeyboard(activity, requireView().windowToken)
}
clearInput()
}
}
}
我在 onViewCreated
回调中初始化它,是的,它工作正常。在不同的片段中做同样的事情会产生......出于某种原因的不同结果。
class BrowseFragment() : Fragment() {
private lateinit var viewModel: ViewModel
var recipeAdapter = RecipeAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_browse, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this).get(ViewModel::class.java)
viewModel.readAllRecipes.observe(viewLifecycleOwner, Observer { recipe -> recipeAdapter.setData(recipe) })
submit_button.setOnClickListener{
var submitFragment = SubmitFragment(recipeAdapter)
var tr = (view.context as FragmentActivity).supportFragmentManager.beginTransaction()
tr.replace(R.id.fragment_container, submitFragment)
tr.commit()
}
browse_recycler_view.apply {
layoutManager = LinearLayoutManager(activity)
adapter = recipeAdapter
}
}
}
当我尝试在 onViewCreated
中初始化视图模型时,出现 IllegalStateException: Can't access ViewModels from detached fragment
异常。在 onCreate
中创建它也不起作用,因为生命周期所有者为空,我想这是有道理的。我到底做错了什么?