Неправильное отображение в recycler view с databinding и livedata

Приложение для работы с api простое. Recyclerview содержит card view. Он отображает элементы, но делает это хаотично. Не правильно. Я использую databinding вместе с viewmodel. Для наблюдения livadata. Я знаю, что нужно указать жизненный цикл для livedata и я это сделал. Я не понимаю почему отображается неправильно. То-есть для всех элементов в экране отображается данные одного объекта. Листая recyclerview Они сменяются на самого нижнего на экране. Я думаю проблема в наблюдении, но в чём конкретно не понимаю. Работа с api правильна. Отображение картинок через Picasso правильная. То есть он правильно отображает то, что не связанно databinding. Проблема именно в нём

Код xml файла

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="viewModel"
            type="com.fraime.android.rm.presentation.ui.list.ListViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:cardBackgroundColor="#FFE502"
            app:cardCornerRadius="20dp"
            app:cardPreventCornerOverlap="true"
            app:cardUseCompatPadding="true"
            app:contentPadding="5dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <ImageView
                    android:id="@+id/iconCharacter"
                    android:layout_width="78dp"
                    android:layout_height="82dp"
                    android:layout_marginStart="16dp"
                    android:layout_marginTop="16dp"
                    android:layout_marginBottom="16dp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    tools:srcCompat="@tools:sample/avatars" />

                <TextView
                    android:id="@+id/nameCharacter"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="16dp"
                    android:layout_marginEnd="16dp"
                    android:text="@{viewModel.name}"
                    android:textColor="#000000"
                    android:textSize="20sp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toEndOf="@+id/iconCharacter"
                    app:layout_constraintTop_toTopOf="parent"
                    tools:text="Rick Sanchez" />

                <TextView
                    android:id="@+id/speciesCharacter"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="16dp"
                    android:text="@{viewModel.species}"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toEndOf="@+id/iconCharacter"
                    app:layout_constraintTop_toBottomOf="@+id/nameCharacter"
                    tools:text="Human" />

                <TextView
                    android:id="@+id/genderCharacter"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="16dp"
                    android:layout_marginBottom="16dp"
                    android:text="@{viewModel.gender}"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toEndOf="@+id/iconCharacter"
                    app:layout_constraintTop_toBottomOf="@+id/speciesCharacter"
                    tools:text="Male" />
            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.cardview.widget.CardView>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

код viewmodel

package com.fraime.android.rm.presentation.ui.list

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.fraime.android.rm.domain.model.Character
import com.fraime.android.rm.domain.usecase.GetCharactersUseCase

class ListViewModel(getCharactersUseCase: GetCharactersUseCase) : ViewModel() {

    val listCharacter : LiveData<List<Character>>

    init {
        listCharacter = getCharactersUseCase.execute()
    }
    var _name: MutableLiveData<String?> = MutableLiveData()
    val name : LiveData<String?> = _name

    var _species: MutableLiveData<String?> = MutableLiveData()
    val species: LiveData<String?> = _species

    var _gender: MutableLiveData<String?> = MutableLiveData()
    val gender: LiveData<String?> = _gender

    var character: Character? = null
        set(character) {
            field = character
            _name.postValue(character?.name)
            _species.postValue(character?.species)
            _gender.postValue(character?.gender)
        }
}


код фрагмента (я специально сделал адаптер во фрагменте потому что у же не понимаю в чем проблема и совсем отчаился)

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.fraime.android.rm.R
import com.fraime.android.rm.databinding.FragmentListBinding
import com.fraime.android.rm.databinding.FragmentListItemBinding
import com.fraime.android.rm.domain.model.Character
import com.squareup.picasso.Picasso
import org.koin.androidx.viewmodel.ext.android.viewModel

class ListFragment : Fragment() {
    private lateinit var binding: FragmentListBinding
    private val listViewModel by viewModel<ListViewModel>()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_list, container, false)
        binding.recyclerView.apply {
            layoutManager = LinearLayoutManager(context)
        }
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        listViewModel.listCharacter.observe(viewLifecycleOwner){
            binding.recyclerView.adapter = RcAdapter(it)
        }
    }

    private inner class CharacterViewHolder(private val binding: FragmentListItemBinding) :
        RecyclerView.ViewHolder(binding.root) {
        init {
            binding.viewModel = listViewModel
        }

        fun bind(character: Character) {
            Picasso.get()
                .load(character.image)
                .into(binding.iconCharacter)
            binding.apply {
                viewModel?.character = character
                executePendingBindings()
            }
        }

    }
    private inner class RcAdapter(private val characters: List<Character>) :
        RecyclerView.Adapter<CharacterViewHolder>() {

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CharacterViewHolder {
            val binding = DataBindingUtil.inflate<FragmentListItemBinding>(
                layoutInflater,
                R.layout.fragment_list_item,
                parent,
                false
            )
            binding.lifecycleOwner = this@ListFragment
            return CharacterViewHolder(binding)
        }

        override fun onBindViewHolder(holder: CharacterViewHolder, position: Int) {
            holder.bind(characters[position])
        }

        override fun getItemCount() = characters.size
    }

}

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

Автор решения: Fraime

Разобрался с данной проблемой. Всё как всегда оказалось супер легко и просто Сначала я писал binding.viewModel = MyViewModel в блоке init View Holder

private inner class RcAdapter(private val characters: List<Character>) :
        RecyclerView.Adapter<RcAdapter.CharacterViewHolder>() {
        private inner class CharacterViewHolder(private val binding: FragmentListItemBinding) :
            RecyclerView.ViewHolder(binding.root) {

            init {
                binding.viewModel = ListItemViewModel() //Вот это место
            }

            fun bind(character: Character) {
                binding.apply {
                    Picasso.get()
                        .load(character.image)
                        .into(binding.iconCharacter)
                    viewModel?.character = character
                    executePendingBindings()
                }
            }

        }

Но это связывание с вашей ViewModel нужно делать в функции адаптера onCreateViewHolder

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CharacterViewHolder {
            val binding = DataBindingUtil.inflate<FragmentListItemBinding>(
                layoutInflater,
                R.layout.fragment_list_item,
                parent,
                false
            )
            binding.lifecycleOwner = this@ListFragment //Владелец жизненного цикла
            binding.viewModel = ListItemViewModel() //Ваша ViewModel
            return CharacterViewHolder(binding)
        }
→ Ссылка