Listing 26.12 - Using AndroidViewModelFactory instead of Depreciated ViewModelProviders

Like we’ve seen in several earlier chapters ViewModelProviders has been depreciated. If you google fixes for that over the last year, a lot of them will point you toward using ViewModelProvider which has also just recently been depreciated.

I found a real nice article that’s actually been updated twice in the last month (Oct & Nov '21), which helped me get the code working with an AndroidViewModelFactory.

The code from Listing 26.12 ended up looking like below.

PhotoGalleryViewModel.kt

class PhotoGalleryViewModel (app: Application) : AndroidViewModel (app) {

    val galleryItemLiveData: LiveData<List<GalleryItem>>

    private val flickrFetchr = FlickrFetchr()
    private val mutableSearchTerm = MutableLiveData<String>()

    val searchTerm: String
        get() = mutableSearchTerm.value ?: ""

    init {
        val str = QueryPreferences.getStoredQuery(getApplication())
        mutableSearchTerm.value = str
        Log.d (TAG, "Read Search Term: $str")
        galleryItemLiveData =
            Transformations.switchMap(mutableSearchTerm) { searchTerm ->
                if (searchTerm.isBlank()) {
                    flickrFetchr.fetchPhotos()
                } else {
                    flickrFetchr.searchPhotos(searchTerm)
                }
            }
    }

    fun fetchPhotos (query: String = "") {
        QueryPreferences.setStoredQuery (getApplication(), query)
        mutableSearchTerm.value = query
    }
}


class PhotoGalleryViewModelFactory (private val app: Application)
    : ViewModelProvider.AndroidViewModelFactory (app) {
}

And the harder part to get fixed was the code where the PhotoGalleryViewModel is created back in PhotoGalleryFragment init. It turned out to be simple in the end, but it took a lot of trial and error before I fund the right magic dust.

PhotoGalleryFragment.kt:

class PhotoGalleryFragment : Fragment() {

    private lateinit var photoGalleryViewModel: PhotoGalleryViewModel
    private lateinit var photoRecyclerView: RecyclerView
    private lateinit var thumbnailDownloader: ThumbnailDownloader<PhotoHolder>

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

        //retainInstance = true  // Depreciated
        setHasOptionsMenu(true)

        val viewModel: PhotoGalleryViewModel by viewModels {
            PhotoGalleryViewModelFactory (requireActivity().application)
        }
        photoGalleryViewModel = viewModel

        val responseHandler = Handler (Looper.getMainLooper())
        thumbnailDownloader =
            ThumbnailDownloader (responseHandler) { photoHolder, bitmap ->
                val drawable = BitmapDrawable (resources, bitmap)
                photoHolder.bindDrawable (drawable)
            }
        lifecycle.addObserver(thumbnailDownloader.fragmentLifecycleObserver)
    }