Не обновляется список RecyclerView после добавления объекта в базу данных

Рейтинг: 0Ответов: 1Опубликовано: 02.03.2023

В фрагменте я делаю запрос на добавление города в базу данных, он успешно добавляется, я проверил базу после нажатия кнопки, там плюс 1 объект. Далее вызываю метод getAll() чтобы обновить слушатель liveData,и подписываюсь на изменения в своем фрагменте. Далее в адаптеру передаю новый список и в сеттере вызываю notifyDataSetChanged(). Обновления списка срабатывает только при перезапуске фрагмента. Метод удаления из списка срабатывает, но не всегда с первого раза.

class MainViewModel : ViewModel() {

private val database = App.instance.getDatabase()

private val fiveDaysWeather = MutableLiveData<String>()
private val allCities = MutableLiveData<List<City>>()
fun getAllCities(): LiveData<List<City>> = allCities
fun getWeather(): MutableLiveData<String> = fiveDaysWeather

fun getAll() {
    viewModelScope.launch(Dispatchers.IO) {
        val citiesDB = database.cityDao().getAll()
        allCities.postValue(citiesDB)
    }
}

fun insert(city: City) {
    viewModelScope.launch(Dispatchers.IO) {
        val existingCity = database.cityDao().getCityByName(city.name)
        if (existingCity == null) {
            database.cityDao().insert(city)
            getAll()
        } else {
            city.uid = existingCity.uid
            database.cityDao().update(city)
        }
    }
  }

    class CitiesAdapter(private val cityActionListener: CityActionListener) :
    RecyclerView.Adapter<CitiesAdapter.CitiesViewHolder>(), View.OnClickListener {

    class CitiesViewHolder(val binding: ItemCityBinding) : RecyclerView.ViewHolder(binding.root)

    override fun onClick(v: View) {
        val city = v.tag as City
        when (v.id) {
            R.id.deleteCityButton -> {
                cityActionListener.onCityDelete(city)
            }
            else -> {
                cityActionListener.onCityDetails(city)
            }
        }
    }

    var cities: List<City> = listOf()
        set(newValue) {
            field = newValue
            notifyDataSetChanged()
        }

    override fun getItemCount(): Int = cities.size

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CitiesViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = ItemCityBinding.inflate(inflater, parent, false)

        binding.root.setOnClickListener(this)
        binding.deleteCityButton.setOnClickListener(this)
        return CitiesViewHolder(binding)
    }

    override fun onBindViewHolder(holder: CitiesViewHolder, position: Int) {
        val city = cities[position]
        with(holder.binding) {
            holder.itemView.tag = city
            deleteCityButton.tag = city
            nameTextView.text = city.name
            temperatureTextView.text = city.weatherList[0].temperature
            precipitationTextView.text = city.weatherList[0].precipitation
            windSpeedTextView.text = city.weatherList[0].wind_speed
            imageViewMainDescription.setImageResource(city.weatherList[0].image)
        }
    }

}

    class CitiesFragment : Fragment() {

    private lateinit var adapter: CitiesAdapter
    private lateinit var viewModel: MainViewModel
    private lateinit var onDataPass: OnDataPass
    private var _binding: FragmentCitiesBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        viewModel = ViewModelProvider(this)[MainViewModel::class.java]
        _binding =  FragmentCitiesBinding.inflate(inflater, container, false)
        adapter = CitiesAdapter(object : CityActionListener{
            /**Метод удаления и обновления списка*/
            override fun onCityDelete(city: City) {
                viewModel.delete(city)
                viewModel.getAll()
                adapter.notifyDataSetChanged()
            }
            override fun onCityDetails(city: City) {
                onDataPass.updateUICity(city)
                activity?.supportFragmentManager?.popBackStack()
            }
        })
        val layoutManager = LinearLayoutManager(activity)
        binding.recyclerviewFragment.layoutManager = layoutManager
        binding.recyclerviewFragment.adapter = adapter
        return binding.root
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        onDataPass = context as OnDataPass
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel.getAllCities().observe(viewLifecycleOwner, Observer {
            adapter.cities = it
        })
        viewModel.getAll()
        binding.writeCityEditTextFragment.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                return@setOnEditorActionListener findCity()
            }
            return@setOnEditorActionListener false
        }
    }

    private fun findCity(): Boolean {
        return if (binding.writeCityEditTextFragment.text.toString() == "") {
            Toast.makeText(App.instance, "Введите город для поиска!", Toast.LENGTH_SHORT).show()
            true
        } else {
            binding.writeCityEditTextFragment.hideKeyboard()
            val cityName = binding.writeCityEditTextFragment.text.toString().trim()
            onDataPass.findNewCity(cityName)
            false
        }
    }

    private fun View.hideKeyboard() {
        val inputManager =
            context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        inputManager.hideSoftInputFromWindow(windowToken, 0)
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}

Ответы

▲ 0Принят

Потратил очень много времени на решение этого вопроса и надеюсь это поможет. Ошибку помог найти ответ отсюда Похожий вопрос Проблема была в получении LiveData, которую не видел адаптер. Добавил новый метод в Dao для прослушивания изменений базы данных:

@Query("SELECT * FROM city")
fun getUpdateDB(): LiveData<List<City>>

в фрагменте повесил слушатель

 viewModel.database.cityDao().getUpdateDB().observe(viewLifecycleOwner, Observer {
        adapter.submitList(it)
    })

и изменил адаптер

    var cities = mutableListOf<City>()

fun submitList(newData: List<City>) {
    cities.clear()
    cities.addAll(newData)
    notifyDataSetChanged()
}