当前位置: 首页 > 知识库问答 >
问题:

房间在使用实时数据时返回空值,但在未使用实时数据包装时返回正确的值

江琦
2023-03-14

我正在使用以下DAO

@Dao
interface GroceryListDao {

@Insert
fun insert(list: GroceryList)

@Update
fun update(list: GroceryList)

@Query("Delete from grocery_list_table")
fun clear()

@Query ("Select * from grocery_list_table")
fun getAllItems(): LiveData<List<GroceryList>>

@Query ("Select * from grocery_list_table where itemId = :item")
fun getItem(item: Long): GroceryList?

@Query ("Select * from grocery_list_table where item_status = :status")
fun getItemsBasedOnStatus(status: Int): List<GroceryList>


}

我的数据库有3列杂货店ID(Long-auto生成的)、杂货店名称(String)和杂货店状态(Int-1/0)。

当我在不使用LiveData的情况下使用getItemsBasedOn状态(状态:Int)时,我能够检索数据。但是当它被LiveData包装时,我变得为空。

另一个问题是,当我从数据库中获取项目列表时,没有使用LiveData包装并在ViewModel中分配给MutableLiveData,那么分配的MutableLiveData将显示空值。我看到很多问题,但没有答案。

为我的viewModel和Fragment添加代码

视图模型

class GroceryListViewModel(
val database: GroceryListDao,
application: Application
) : AndroidViewModel(application) {

private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

var grocerylistItems = database.getAllItems()
var groceryItem = MutableLiveData<GroceryList>()
var groceryitems = MutableLiveData<List<GroceryList>>()

init {
    getAllItemsFromDatabase()
}

fun insertIntoDatabase(item: GroceryList) {
    uiScope.launch {
        insert(item)
    }
}

private suspend fun insert(item: GroceryList) {
    withContext(Dispatchers.IO) {
        database.insert(item)
    }
}

fun updateGrocerylist(itemId: Long, status: Int) {
    uiScope.launch {
        groceryItem.value = getItem(itemId)
        groceryItem.value?.itemStatus = status
        groceryItem.value?.let { update(it) }

    }
}

private suspend fun update(item: GroceryList) {
    withContext(Dispatchers.IO) {
        database.update(item)
    }
}


private suspend fun getItem(itemId: Long): GroceryList? {
    return withContext(Dispatchers.IO) {
        var item = database.getItem(itemId)
        item
    }
}

fun getAllItemsFromDatabase() {
    uiScope.launch {
        getAllItems()
    }
}

private suspend fun getAllItems() {
    withContext(Dispatchers.IO) {
        grocerylistItems = database.getAllItems()


    }
}

fun getPendingItemsFromDatabase(status: Int) {
    uiScope.launch {
        getPendingItems(status)
    }
}

private suspend fun getPendingItems(status: Int) {
    withContext(Dispatchers.IO) {
        val items = database.getItemsBasedOnStatus(status)
        groceryitems.postValue(items)
        Log.i("Grocery List", "Pending Items:" + items.size)

    }
}

fun getDoneItemsFromDatabase(status: Int) {
    uiScope.launch {
        getDoneItems(status)
    }
}

private suspend fun getDoneItems(status: Int) {
    withContext(Dispatchers.IO) {
        val items = database.getItemsBasedOnStatus(status)
        groceryitems.postValue(items)
        Log.i("Grocery List", "Done Items:" + items.size)
    }
}

fun clearAllItemsFromDatabase() {
    uiScope.launch {
        clearItems()
    }
}

private suspend fun clearItems() {
    withContext(Dispatchers.IO) {
        database.clear()
        getAllItemsFromDatabase()
    }
}

override fun onCleared() {
    super.onCleared()
    viewModelJob.cancel()
}

}

碎片

class GroceryLIstFragment : Fragment() {

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    val binding = FragmentGroceryLIstBinding.inflate(inflater,container,false)

    val application = requireNotNull(this.activity).application
    val dataSource = GroceryDatabase.getInstance(application)?.groceryListDatabaseDao

    val viewModelFactory = dataSource?.let { GroceryListViewModelFactory(it, application) }

    val viewModel = viewModelFactory?.let {
        ViewModelProvider(
            this,
            it
        ).get(GroceryListViewModel::class.java)
    }

    viewModel?.grocerylistItems?.observe(this , Observer {
        binding.grocerylistView.removeAllViews() // is it correct ?
        for (item in it){
            Log.i("Grocery List","Grocery Id=" + item.itemId+" ,Grocery Name=" + item.itemName +", Grocery status="+item.itemStatus)
            addItemToScrollbar(item, binding, viewModel)
        }
    })


    binding.addGrocery.setOnClickListener {

        val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(view?.windowToken, 0)

        val item = binding.groceryitemField.text.toString()

        if (!item.isNullOrBlank()) {
            val newItem = GroceryList(itemName = item)
            viewModel?.insertIntoDatabase(newItem)
            if (viewModel != null) {
                addItemToScrollbar(newItem, binding,viewModel)
            }
            binding.groceryitemField.text.clear()
        }
    }

    binding.doneCheckbox.setOnClickListener {
        if (binding.doneCheckbox.isChecked)
            viewModel?.getDoneItemsFromDatabase(1)
        else
            viewModel?.getAllItemsFromDatabase()

    }

    binding.pendingCheckbox.setOnClickListener {
        if (binding.pendingCheckbox.isChecked) {
            viewModel?.getPendingItemsFromDatabase(0)
        }
        else
            viewModel?.getAllItemsFromDatabase()

    }

    binding.clearGrocery.setOnClickListener {
        viewModel?.clearAllItemsFromDatabase()
        binding.grocerylistView.removeAllViews()
    }

    return binding.root
}

private fun addItemToScrollbar(
    item: GroceryList,
    binding: FragmentGroceryLIstBinding,
    viewModel: GroceryListViewModel
) {
    val itemBox = AppCompatCheckBox(context)
    itemBox.text = item.itemName
    itemBox.isChecked = item.itemStatus == 1
    binding.grocerylistView.addView(itemBox)
    itemBox.setOnClickListener {
        val itemstatus: Int = if (itemBox.isChecked)
            1
        else {
            0
        }
        viewModel?.updateGrocerylist(item.itemId,itemstatus)

    }

}

}

任何帮助都将不胜感激。

共有1个答案

红弘盛
2023-03-14

这很可能与这里的问题相同(阅读链接答案)。由于LiveData的异步工作方式,当您调用它时,它将返回null。LiveData旨在与观察者一起使用,一旦观察对象发生变化,就会触发。

观察者可以是这样的

    database.getItemsBasedOnStatus(status).observe(viewLifecycleOwner, Observer  { groceryList->
    // Do cool grocery stuff here

    })

如果你想在你的ViewModel中检索你的数据,你没有一个view生命周期所有者,你可以使用“观察永远()”,但是你必须显式地删除观察者,见这个答案。

同样的问题和答案也出现在这篇文章中

 类似资料:
  • 所以我当前处于“America/Los_Angeles”时区(PDT)中,但是当我创建一个新的moment对象并通过moment tz将其时区设置为我所在的时区('America/Los_Angeles'),如下所示: 错误的时间被返回。具体来说就是提前8个小时。所有其他时区也会出现这种情况。 我是不是从根本上误解了这是怎么工作的? 谢谢你的帮助!

  • 我似乎不知道为什么当我使用lambda时需要从方法返回一些东西时,我在IDE上会出现这个错误。 非常感谢。

  • 我试图通过使用基于索引的行位置简单地获得df的子集。但是,出于某些原因,以下代码有时返回空数据帧: dist数据帧(帧是索引): 输出: 我一辈子都不明白为什么会发生这种事。

  • 我有如下疑问, 我通过如下传递值来调用服务方法。 但它回来了。。。[] 帮助我为什么我没有得到值,而是得到了空列表。 附言:我检查了日志,它的语句是创建的,没有任何问题

  • null 如果有人知道如何解决这个问题,或一个可供选择的方法,请发表评论。 如有任何帮助,我们将不胜感激。

  • 我是Android开发的新手,当然还有碎片。 我想访问main activity中我的片段的控件,但是'find viewbyid'返回null。如果没有片断,代码可以正常工作。