Некорректная работа RecyclerView с LiveData

Учусь работать с LiveData, ViewModel и RecyclerView. В приложении два фрагмента. В первом список элементов, второй добавляет новый элемент. После добавления фрагмент закрывается, возвращаясь в список. Проблема в том, что onChange в LiveData вызывается два раза, в адаптер набор данных передается два раза. Один раз предыдущий набор данных и второй раз уже новый. Из-за этого в списке элементы перемешиваются.

LogCat при запуске:

    2020-09-06 11:31:42.459 25304-25304/ru.albeiz.equipmover D/TAG: Get Live Data
    2020-09-06 11:31:42.460 25304-25304/ru.albeiz.equipmover D/TAG: Setting itemList

После я запускаю второй фрагмент и как результат добавляю новый элемент в БД. Затем этот фрагмент закрывает и управление возвращается во второй. При этом LogCat следующий:

    2020-09-06 11:32:19.669 25304-25304/ru.albeiz.equipmover D/TAG: Get Live Data
    2020-09-06 11:32:19.669 25304-25304/ru.albeiz.equipmover D/TAG: Setting itemList
    2020-09-06 11:32:19.838 25304-25304/ru.albeiz.equipmover D/TAG: Get Live Data
    2020-09-06 11:32:19.839 25304-25304/ru.albeiz.equipmover D/TAG: Setting itemList

То есть OnChange срабатывает 2 раза и адаптер списка получает набор элементов дважды. Сначала старый набор (до нового элемента), после новый. На экране recycler показывает перемешанные элементы. Если я снова запускаю второй фрагмент и закрываю его, не вводя ничего, то список уже показывает всё как надо. То же происходит и после перезапуска приложения.

Вопрос в том как это исправить и почему так происходит?

class FirstFragment : Fragment() {

private val TAG = "FirstFragment"

private lateinit var mViewModel: EquipViewModel
private lateinit var mAdapter: EquipAdapter


override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_equip_list, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    fab.setOnClickListener {
        mNewMoveCaller.createNewMove()
    }

    initRecyclerView()

    mViewModel = ViewModelProvider(requireActivity()).get(EquipViewModel::class.java)

    mViewModel.getAllMoves().observe(viewLifecycleOwner, Observer{
        Log.d("TAG", "Get Live Data")
        mAdapter.setList(it)
    })

}

private fun initRecyclerView() {
    mAdapter = EquipAdapter()

    recyclerView.apply {
        layoutManager = LinearLayoutManager(activity)
        setHasFixedSize(true)
        adapter = mAdapter
    }
}

}


class SecondFragment : Fragment() {

private lateinit var mViewModel: EquipViewModel


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setHasOptionsMenu(true)
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    inflater.inflate(R.menu.menu_new_move, menu)
    super.onCreateOptionsMenu(menu, inflater)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    when (item.itemId) {
        R.id.miSaveMove -> {
            saveNewMove()
        }
    }

    return true
}

private fun saveNewMove() {
    
        val newEquipMove = EquipMove(
            null,
            etNewCode.text.toString(),
            Date().time,
            //"spDestination.selectedItem.toString()"
            "someText"
        )
        mViewModel.insert(newEquipMove)
        exitFragment()
    
}

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_new_move, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val activity = requireActivity() as AppCompatActivity
    activity.setSupportActionBar(frag_new_move_toolbar)
    activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
    activity.supportActionBar?.title = "Add a new move"

    frag_new_move_toolbar.setNavigationOnClickListener {
        exitFragment()
    }

    mViewModel = ViewModelProvider(requireActivity()).get(EquipViewModel::class.java)

    btnSaveNewMove.setOnClickListener {
        saveNewMove()
    }

}

private fun exitFragment() {
    requireActivity().onBackPressed()
}

}



class EquipAdapter(private var itemList: List<EquipMove> = listOf()): 
RecyclerView.Adapter<EquipAdapter.EquipViewHolder>() {

inner class  EquipViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EquipViewHolder {
    val view = LayoutInflater.from(parent.context)
        .inflate(R.layout.recview_item, parent, false)
    return EquipViewHolder(view)
}

override fun getItemCount(): Int {
    return itemList.size
}

override fun onBindViewHolder(holder: EquipViewHolder, position: Int) {
    holder.itemView.apply {
        tvEquipmentCode.append(itemList[position].equipCode)
        tvDestination.append(itemList[position].moveDestination)
        tvMoveDate.append(itemList[position].moveDate.toString())
    }
}

fun setList(itemList: List<EquipMove>) {
    this.itemList = itemList
    notifyDataSetChanged()
    Log.d("TAG", "Setting itemList")
}

}


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

private val equipRepository = EquipRepository(application)
private val allMoves = equipRepository.getAllMoves()


fun insert(equipMove: EquipMove) {
    viewModelScope.launch {
        equipRepository.insert(equipMove)
    }
}

fun deleteAll() {
    viewModelScope.launch {
        equipRepository.deleteAll()
    }
}

fun delete(equipMove: EquipMove) {
    viewModelScope.launch {
        equipRepository.delete(equipMove)
    }
}

fun getAllMoves() : LiveData<List<EquipMove>> {
    return allMoves
}

}

Ответы (0 шт):