Utknąłem próbując dowiedzieć się, jak zaktualizować listę, którą pokazuje mój recykleryk.

Co próbuję zrobić, to pokazać podzbiór widocznej listy, gdy wirowa zostanie zmieniona. Mam zbiór zwierząt w mojej bazie danych, a niektóre mają swój atrybut pet jako true i inni mają ustawione jako false.

Korzystanie z bazy danych pokojowych z repozytoriami i roślinnymi, a co próbowałem razem spięść, jest to, że dobrze jest mieć trzy różne listy, które mogę dostroić, więc w m

Magazyn:

class AnimalRepository(private val animalDao: AnimalDao) {
    val allAnimals: Flow<List<Animal>> = animalDao.getAnimalsByCategory()
    val pets: Flow<List<Animal>> = animalDao.getAnimalsByPetStatus(true)
    val nonPets: Flow<List<Animal>> = animalDao.getAnimalsByPetStatus(false)

    @Suppress("RedundantSuspendModifier")
    @WorkerThread
    suspend fun insert(animal: Animal) {
        animalDao.insert(animal)
    }

    @WorkerThread
    suspend fun get(id: Int): Animal {
        return animalDao.get(id)
    }

    @WorkerThread
    suspend fun delete(id: Int) {
        animalDao.delete(id)
    }
}

ViewModel

class AnimalViewModel(private val repository: AnimalRepository) : ViewModel() {

    var allAnimals: LiveData<List<Animal>> = repository.allAnimals.asLiveData()
    val pets: LiveData<List<Animal>> = repository.pets.asLiveData()
    val nonPets: LiveData<List<Animal>> = repository.nonPets.asLiveData()
    var result: MutableLiveData<Animal> = MutableLiveData<Animal>()
    var mode: VIEW_MODES = VIEW_MODES.BOTH

    /*
    * Launching a new coroutine to insert the data in a non-blocking way
    * */
    fun insert(animal: Animal) = viewModelScope.launch {
        repository.insert(animal)
    }

    /*
    * Launching a new coroutine to get the data in a non-blocking way
    * */
    fun get(id: Int) = viewModelScope.launch {
        result.value = repository.get(id)
    }

    fun delete(id: Int) = viewModelScope.launch {
        repository.delete(id)
    }
}

class AnimalViewModelFactory(private val repository: AnimalRepository) : ViewModelProvider.Factory {
    override fun <T: ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(AnimalViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return AnimalViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

W moim MainActivity Utworzono, gdzie mam obserwator na tych trzech listach i w zależności od tego, który tryb widoku jest aktywny (wirowe ustawia tryb widoku), ta lista jest podawana do listy przemitrowatej My Recylekterview's Listadaptera

animalViewModel.allAnimals.observe(this) { animals ->
    if (viewMode == VIEW_MODES.BOTH) {
        animals.let {
            adapter.submitList(it)
            // recyclerView.adapter = adapter
        }
    }
}
animalViewModel.pets.observe(this) { animals ->
    if (viewMode == VIEW_MODES.PETS) {
        animals.let {
            adapter.submitList(it)
            // recyclerView.adapter = adapter
        }
    }
}
animalViewModel.nonPets.observe(this) { animals ->
    if (viewMode == VIEW_MODES.NON_PETS) {
        animals.let {
            adapter.submitList(it)
        }
    }
}

Zmiana trybu z moim spinną

override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
    when (position) {
        0 -> {
            viewMode = VIEW_MODES.BOTH
        }
        1 -> {
            viewMode = VIEW_MODES.PETS
        }
        2 -> {
            viewMode = VIEW_MODES.NON_PETS
        }
    }
    adapter.notifyDataSetChanged()
}

Działa dobrze, jeśli dodano lub usuń zwierzę po zmianie trybu widoku, ponieważ obserwatorzy ogień, a prawidłowy może wypełnić adapter, ale notifyDataSetChanged() nie robi niczego i utknąłem na zdobycie Adapter do aktualizacji bez konieczności dodawania lub usuwania z list

Próbowałem również zresetować adaptera w obserwatorze, ale nic też nic nie zrobiło

Jestem niezwykle nowa w Kotlin i programowaniu na Androidzie, a jestem pewien, że idę na to niewłaściwy sposób, ale czy istnieje sposób odświeżanie listy?


Aktualizacja:

Myślę, że mogłem znaleźć rozwiązanie, ale martwię się, że to hacky. W moim ViewModel zastępuję zawartość mojego allAnimals za pomocą filtrowanych list


    fun showBoth() {
        allAnimals = repository.allAnimals.asLiveData()
    }
    fun showPets() {
        allAnimals = repository.pets.asLiveData()
    }
    fun showNonPets() {
        allAnimals = repository.nonPets.asLiveData()
    }

A potem w mojej głównej działalności zmieniłem logikę podczas obchodzenia się z zmianą wirowania, aby powiedzieć o modelu, aby zrobić swoją rzecz, a następnie usunąć obserwatora i uderzył go z powrotem

override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
    when (position) {
        0 -> {
            animalViewModel.showBoth()
        }
        1 -> {
            animalViewModel.showPets()
        }
        2 -> {
            animalViewModel.showNonPets()
        }
    }
    refreshObserver()
}

private fun refreshObserver() {
    animalViewModel.allAnimals.removeObservers(this)
    animalViewModel.allAnimals.observe(this) { animals ->
        animals.let {
            adapter.submitList(it)
        }
    }
}

Wydaje się, że działa, aby uzyskać widok recyklera do aktualizacji, ale czy jest hacky?

0
Samuel 13 marzec 2021, 00:35

1 odpowiedź

Najlepsza odpowiedź

O ile widzę, to ma sens, że notifyDataSetChanged nie robi niczego, nie przesyłasz żadnych nowych danych przed tym połączeniem. Jednak myślę, co próbujesz zrobić, to uzyskać adapter do reagowania na zmianę {x1}}.

Jeśli tak jest, polecam również posiadanie viewMode jako obiekt LiveData, a następnie odsłonić pojedynczą listę dla adaptera, aby obserwować, co zmienia się w zależności od wybranej viewMode.

Metoda Transformations.switchMap(LiveData<X>, Function<X, LiveData<Y>>) (lub jego równoważna funkcja rozszerzenia Kotlin) prawdopodobnie zrobiłaby prawdopodobnie większość prac dla Ciebie tutaj. Podsumowując mapuje wartości jednego LiveData do drugiego. Więc w twoim przykładzie można mapować swój viewMode do jednego z allAnimals, pets i nonPets.

Oto prosty przegląd pseudokodów dla jakiejś jasności:

AnimalViewModel {

    val allAnimals: LiveData<List<Animal>>
    val pets: LiveData<List<Animal>>
    val nonPets: LiveData<List<Animal>>

    val modes: MutableLiveData<VIEW_MODES>

    val listAnimals = modes.switchMap {
        when (it) {
            VIEW_MODES.BOTH -> allAnimals
            ...
        }
    }
}
fun onItemSelected {
    
    viewModel.onModeChanged(position)
}
viewModel.listAnimals.observe {

    adapter.submitList(it)
}
2
Henry Twist 13 marzec 2021, 22:34