【问题标题】:Room LiveData Problem When App First Installed首次安装应用程序时的房间 LiveData 问题
【发布时间】:2020-11-30 11:18:16
【问题描述】:

我正在开发一个应用程序作为培训。目前,如果互联网连接可用,它会调用 api 并将数据加载到 Room,同时 UI 会显示来自 Room 的数据。首次启动后它工作正常,但是当我将它安装到新的设备模拟器等或重新安装它时。它在第一次启动时不显示数据,但如果我关闭它并再次打开。它继续正常工作。我该如何解决这个问题? 这是我的代码:

CityDao

  interface CityDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun addCity(cityRm: CityRm)

    @Query("SELECT * FROM city_table ORDER BY cId ASC")
    suspend fun readAllCities(): List<CityRm>
}

CityRoomRepository

   class CityRoomRepository(private val cityDao: CityDao) {

    suspend fun readAllCities(): List<CityRm> {
        return cityDao.readAllCities()
    }

    suspend fun addCity(cityRm: CityRm) {
        cityDao.addCity(cityRm)
    }

}

城市模型视图

class   CityRmViewModel (application: Application):AndroidViewModel(application) {

    val allCities = MutableLiveData<List<CityRm>>()
    private val cityDao = EventsDatabase.getEventsDatabase(application).cityDao()
    private val eventDao = EventsDatabase.getEventsDatabase(application).eventDao()
    private val cityRoomRepository: CityRoomRepository = CityRoomRepository(cityDao)
    private val cityRepository: CityRepository = CityRepository()
    private val eventRepository: EventListRepository = EventListRepository()
    private val eventRoomRepository: EventsRoomRepository = EventsRoomRepository(eventDao)

    init {
        viewModelScope.launch(Main) {
            val cities = cityRoomRepository.readAllCities()
            allCities.value = cities
        }
        viewModelScope.launch(IO) {
            try {
                if (InternetConnectionCheck(application)) {
                    callCityApi(cityRepository, cityRoomRepository)
                }
            } catch (e: Exception) {
                Log.e("internet connection check error ", e.toString())
            }
        }
        viewModelScope.launch(IO) {
            try {
                if (InternetConnectionCheck(application)) {
                    callEventApi(eventRepository, eventRoomRepository)
                }
            } catch (e: Exception) {
                Log.e("internet connection check error ", e.toString())
            }
        }
    }

    suspend fun loadData() {
        val cities = cityRoomRepository.readAllCities()
        allCities.value = cities
    }
    
}

城市碎片

class citySelectionPage : Fragment() {

    lateinit var cityViewModel: CityRmViewModel
    private val cityAdapter = cityScPageAdapter(arrayListOf())
    
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val view = inflater.inflate(R.layout.fragment_city_selection_page, container, false)

        cityViewModel = ViewModelProvider(this).get(CityRmViewModel::class.java)
        lifecycleScope.launch(Main) {
            cityViewModel.loadData()
        }

        val recyclerView = view.cityPageRecycler
        recyclerView.apply {
            layoutManager = LinearLayoutManager(activity)
            adapter = cityAdapter
        }

        observeViewModel()
        return view
    }

    fun observeViewModel(){
        cityViewModel.allCities.observe(viewLifecycleOwner, { cities ->
            cities?.let {
                cityAdapter.updateCities(it)
            }
        })
    }
}

城市适配器

class cityScPageAdapter(var myCities: ArrayList<CityRm>) :
    RecyclerView.Adapter<cityScPageAdapter.cityScPageViewHolder>() {


    fun updateCities(newCities: List<CityRm>) {
        myCities.clear()
        myCities.addAll(newCities)
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): cityScPageViewHolder {
        return cityScPageViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_cities, parent, false)
        )
    }

    override fun onBindViewHolder(holder: cityScPageViewHolder, position: Int) {
        holder.itemView.setOnClickListener {
            SingletonCityID.cityID = myCities[position].cId
            val action = citySelectionPageDirections.goToEventListPage()
            Navigation.findNavController(it).navigate(action)
        }
        holder.bind(myCities[position])
    }

    override fun getItemCount(): Int {
        Log.d("live data size",myCities.size.toString())
        return myCities.size
    }

    class cityScPageViewHolder(view: View): RecyclerView.ViewHolder(view){

        private val cityName = view.findViewById<TextView>(R.id.cityName)

        fun bind(myCity: CityRm) {
            cityName.text = myCity.name
        }
    }

}

编辑:当我使用 LiveData 而不是 List 时出错,如果我尝试使用 MutableLiveData(对于 CityRm、Dao 和 Repository)也会得到相同的错误日志

【问题讨论】:

  • 我们可以查看您的适配器代码吗?如果您调试此行是否会命中cityAdapter.updateCities(it)
  • @DavidKroukamp 我已经添加了适配器代码并尝试了调试,它成功了,但“it”参数是“0”

标签: android android-room android-livedata


【解决方案1】:

@fatihberatcan 首次启动时为空,原因如下。由于您正在从数据库中加载城市,因此在第一次启动时它不会存在。数据库中还没有城市。您调用 city API 并将其存储在数据库中,但您不会得到任何事件。换句话说,您的片段/UI 不知道城市列表现在在数据库中。您需要像 David Kroukamp 提到的那样使用 Livedata 之类的响应式方式,以便在数据更改时收到通知。

就像你提到的,下次或下次启动应用程序时,城市列表现在在数据库中,因此你会在屏幕上看到它。

【讨论】:

  • 感谢您的回复,我曾想过并尝试过,但 livedata 或 mutablelivedata 都给了我 kapt 错误。 public abstract java.lang.Object readAllCities(@org.jetbrains.annotations.NotNull()" 这是其中之一。如果你愿意,我可以编辑我的问题并给出所有错误日志。最后我想在延迟一点后从数据库中读取会工作,但 IDK 协程很好
  • @fatihberatcan 为此,您可以提出一个单独的问题。我猜你使用了错误的 NOTNULL 注释。
  • @fatihberatcan 或者您可以编辑您的问题以将您的问题包含在错误日志中
  • 我添加了错误日志。实际上它在构建应用程序时给了我这些错误。 Logcat 中没有任何内容,因为它甚至没有通过这些更改构建
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 2022-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-18
相关资源
最近更新 更多