I have three fragment app with a bottom navigation bar and I use NavigationUI to switch. I also have a viewmodel which creates the data (from the assets foolder) and the fragments observe the array list of live data which I use to populate a recycler view.
My problem is whenever I switch fragments, as the fragment is recreated, I do not want the data retrieval to happen every time the fragment is recreated. Hence the use of the viewmodel. But in my case, the data in the viewmodel is not retained. I have attached the fragment and the viewmodel code.I am not sure what is wrong here.
I have tried loggging the number of entries in the aaraylist and it comes back with 0, if I do not call the routine which populates the arraylist.
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)
}
})
}
}
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], ""))
}
}
}
Retrieve the viewmodel by passing viewmodelprovider the fragments parent activity instead of fragment itself.
ViewModelProviders.of(activity).get(SongListViewModel::class.java)