#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 ничего нет, потому что он даже не создается с этими изменениями