Проблема с номером LiveData при первой установке приложения

#android #android-room #android-livedata

#Android #android-комната #Android-LiveData

Вопрос:

Я разрабатываю приложение в качестве обучения. В настоящее время он вызывает api и загружает данные в Room, если доступно подключение к Интернету, и в то же время пользовательский интерфейс показывает данные из Room. Он отлично работает после первой загрузки, но когда я устанавливаю его на новое устройство -эмулятор и т. Д. Или переустанавливаю его. При первой загрузке данные не отображаются, но если я закрою их и снова открою. Он продолжает работать нормально. Как мне это решить? Вот мой код:

СитиДао

   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)
    }

}
 

CityModelView

 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<Список> вместо списка, также получаю тот же журнал ошибок, если я попробую это с помощью MutableLiveData (для CityRm, Dao и репозитория)

Комментарии:

1. Можем ли мы увидеть код вашего адаптера? Если вы выполняете отладку, попадает ли эта строка в хит cityAdapter.updateCities(it) ?

2. @DavidKroukamp Я добавил код адаптера и попробовал отладку, он попадает в строку, но аргумент «it» равен «0»

Ответ №1:

@fatihberatcan При первом запуске он пуст по следующей причине. Поскольку вы загружаете город из базы данных, при первом запуске его там не будет. В базе данных пока нет городов. Вы вызываете city API, и он сохраняет то же самое в базе данных, но вы не получите никакого события для этого. Другими словами, ваш фрагмент / пользовательский интерфейс не знает, что список городов теперь находится в базе данных. Вам нужно использовать какой-нибудь реактивный способ, например Livedata, как упоминал Дэвид Кроукамп, чтобы вы получали уведомления при каждом изменении данных.

Как вы уже упоминали, в следующий раз или при следующем запуске приложения список городов теперь есть в базе данных, поэтому вы видите его на экране.

Комментарии:

1. Спасибо за ответ, я думал об этом и пробовал раньше, но livedata или mutablelivedata оба выдали мне ошибки kapt. общедоступный абстрактный java.lang. Объекты для чтения (@org.jetbrains.annotations. NotNull()» это один из них. Если вы хотите, я могу отредактировать свой вопрос и предоставить весь журнал ошибок. Наконец, я думаю, что чтение из базы данных после небольшой задержки будет работать, но IDK это хорошо согласует

2. @fatihberatcan для этого вы можете задать отдельный вопрос. Я думаю, вы используете неправильную аннотацию NOTNULL.

3. @fatihberatcan Или вы можете отредактировать свой вопрос, чтобы включить вашу проблему в журнал ошибок

4. Я добавил журналы ошибок. На самом деле это дает мне эти ошибки при создании приложения. В Logcat ничего нет, потому что он даже не создается с этими изменениями