ViewModel не сохраняет данные после воссоздания фрагмента - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть приложение с тремя фрагментами с нижней панелью навигации, и я использую NavigationUI для переключения. У меня также есть модель представления, которая создает данные (из объекта foolder), и фрагменты отслеживают список массивов живых данных, которые я использую для заполнения представления переработчика.

Моя проблема заключается в том, что всякий раз, когда я переключаю фрагменты, так какфрагмент воссоздан, я не хочу, чтобы поиск данных происходил каждый раз, когда фрагмент воссоздается. Отсюда и использование модели представления. Но в моем случае данные в viewmodel не сохраняются. Я приложил фрагмент и код модели представления. Я не уверен, что здесь не так.

Я попытался зарегистрировать количество записей в aaraylist, и он возвращается с 0, если я не вызываю подпрограммукоторый заполняет массив.

SongsFragment

private const val TAG = "Songs Fragment"

class SongsFragment : Fragment(), android.widget.SearchView.OnQueryTextListener {

    private val viewmodel: SongListViewModel by lazy { ViewModelProviders.of(this).get(SongListViewModel::class.java)}

    private val songListAdapter = SongListAdapter(arrayListOf())
    private var raga = "All"

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        Log.d(TAG, "onCreateView called")

        return inflater.inflate(R.layout.fragment_songs, container, false)
    }

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

        Log.d(TAG, "onViewCreated called")



        val context: FragmentActivity? = activity

        (activity as AppCompatActivity).supportActionBar?.subtitle = "Songs"

        val assetsPath: AssetManager? = context?.assets
        val assetList = assetsPath?.list("")
        if (assetList != null) {
            for (item in assetList)
                Log.d("SongsFragment", assetsPath.toString() + item)
        }

        arguments?.let {
            raga = SongsFragmentArgs.fromBundle(it).raga
        }

        Log.d("Song Fragment", "Raga passed: " + raga)

        Log.d(TAG, "Number of songs: " + viewmodel.songList.size.toString())

        if (raga == "All") {
            viewmodel.allSongs()
            viewmodel.allSongs(assetsPath!!)
        } else {
            viewmodel.songsForRaga(assetsPath!!, raga)
        }

        Log.d(TAG, ": Songlist size: " + viewmodel.songList.size.toString())


        songList_RecyclerView.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = songListAdapter
        }

        songSearchView.setOnQueryTextListener(this)

        observeViewModel()
    }

    override fun onQueryTextSubmit(query: String): Boolean {

        return false
    }

    override fun onQueryTextChange(newText: String): Boolean {
        Log.i("Song Fragment", "Text change:" + newText.length.toString())

        viewmodel.songSearchFilter(newText)

        return false
    }

    fun observeViewModel() {
        viewmodel.songs.observe(this, Observer { songs ->
            songs?.let {
                Log.d("Song Fragment", "ObserveViewModel")
                songListAdapter.updateSongList(songs)
            }
        })
    }
}

SongListViewModel

private const val TAG = "SongListViewModel"

class SongListViewModel : ViewModel() {

    val songs = MutableLiveData<ArrayList<Song>>()
    var songList = arrayListOf<Song>()

    fun allSongs() {
        songList = getAllSongs()

        songs.value = ArrayList(songList.sortedWith(compareBy({ it.songName })))
    }

    fun allSongs(assetsPath: AssetManager) {

        Log.d(TAG, "allSongs called")
        Log.d(TAG, "Number of songs: " + songList.size.toString())
        getAllSongs(assetsPath)
        songs.value = ArrayList(songList.sortedWith(compareBy({ it.songName })))
    }

    fun songSearchFilter(text: String) {

        var filteredList = arrayListOf<Song>()
        filteredList.clear()

        if (text.length != 0) {
            for (song in songList) {
                if (song.songName.toLowerCase().contains(text)) {
                    filteredList.add(song)
                }

            }
            songs.value = ArrayList(filteredList.sortedWith(compareBy({ it.songName })))

        } else {

            songs.value = ArrayList(songList.sortedWith(compareBy({ it.songName })))
        }


    }

    fun songsForRaga(assetsPath: AssetManager, raga: String) {

        Log.d(TAG, "songsForRaga called")

        var filteredList = arrayListOf<Song>()
        filteredList.clear()
        allSongs(assetsPath)
        for (song in songList) {
            if (song.raga == raga) {
                filteredList.add(song)
            }
        }
        songs.value = ArrayList(filteredList.sortedWith(compareBy({ it.songName })))
    }

fun getAllSongs(assetsPath: AssetManager) {

        Log.d(TAG, "getAllSongs called")
        val bufferedReader = assetsPath.open("test.csv").bufferedReader()
        val lineList = mutableListOf<String>()

        bufferedReader.useLines { lines -> lines.forEach { lineList.add(it) } }
        lineList.forEach {
            val parts = it.split(",")
            songList.add(Song(parts[0], parts[1], parts[2], parts[3], ""))
        }


    }
}

Ответы [ 3 ]

1 голос
/ 05 ноября 2019

Получите модель представления, передав viewmodelprovider родительскую активность фрагментов вместо самого фрагмента.

ViewModelProviders.of (activity) .get (SongListViewModel :: class.java)

0 голосов
/ 05 ноября 2019

Обратите внимание, что нам нужно создать экземпляр ViewModel в области действия, иначе android создаст отдельный экземпляр, а не разделяет тот же экземпляр, и мы не получим данные.

Для фрагмента сделайте это следующим образом:

activity?.let {
    val viewmodel = ViewModelProviders.of(it).get(SongListViewModel::class.java)

     viewmodel.songs.observe(this, Observer { songs ->
            songs?.let {
                Log.d("Song Fragment", "ObserveViewModel")
                songListAdapter.updateSongList(songs)
            }
        })
}
0 голосов
/ 05 ноября 2019

Я не рассматриваю это как ответ, просто небольшое объяснение, ваш жизненный цикл viewModel связан с жизненным циклом ваших фрагментов, поэтому ожидается, что когда вы изменяете фрагменты - он уничтожается и относительно вашей viewModel тоже разрушается. Решение состоит в том, чтобы переместить создание viewmodel в активность и вставить его, как советовал Nezih, но я не уверен, что это лучший вариант.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...