Challenge: Efficient Thumbnail Load

After some research, here is how I set up a tree observer to get the dimensions of the image view when it’s inflated, so we can use the dimension to scale our image.

1- create treeObserver, viewWidth, viewHeight variables in crime fragment:

class CrimeFragment: Fragment(), DatePickerFragment.Callbacks, TimePickerFragment.Callbacks {

   ..........................
 private lateinit var treeObserver: ViewTreeObserver
 private var viewWidth = 0
 private var viewHeight = 0

2- In onCreateView, initialize the treeObserver and apply the GlobalLayoutListiner method to it:

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

treeObserver = photoView.viewTreeObserver
        treeObserver.addOnGlobalLayoutListener {
            viewWidth = photoView.width
            viewHeight = photoView.height
        }

        return view
}

3- change updatePhotoView() method to take two arguments, width and height:

private fun updatePhotoView(width: Int, height: Int) {
        if (photoFile.exists()) {
            val bitmap = getScaledBitmap(photoFile.path, width, height )
            photoView.setImageBitmap(bitmap)
        }

        else {
            photoView.setImageDrawable(null)
        }
    }

Note that, for best practice, the observer should be removed after been used. for more info check:
https://antonioleiva.com/kotlin-ongloballayoutlistener/

1 Like

from: https://developer.android.com/reference/android/view/ViewTreeObserver#isAlive()
if observer is not alive, any call to a method (except isAlive()) will throw an exception.

in CrimeFragment.onStart():

photoView.viewTreeObserver.apply {
        if (isAlive) {
            addOnGlobalLayoutListener {
                updatePhotoView()
            }
        }
    }

in CrimeFragment.updatePhotoView():

private fun updatePhotoView() {
    if (photoFile.exists()) {
        val bitmap = PictureUtils.getScaledBitmap(photoFile.path, photoView.width, photoView.height)
        photoView.setImageBitmap(bitmap)
    } else {
        photoView.setImageBitmap(null)
    }
}

In the book’s package code, I just had to change
getScaledBitmap(photoFile.path, requireActivity())
to
getScaledBitmap(photoFile.path, photoView.width, photoView.height)

Why am I not getting the 0dp issue? I’m assuming it manifests itself by having a 0x0 image in the view.

Hi @BasicBear,

Have you implemented the listener or is it the only change you have made to the code?

Hello @Mason,

Thanks for your post.

I was wondering if you were getting the error “lateinit photoFile is not initialized” error?

It turned out that the view was being displayed before the crime was detected in the crimeLiveData.observer. This meant the photoFile object did not get a chance to be initialized, and calling updatePhotoView(srcHeight, srcWidth) function had no photoFile to use.

Are you calling the new updatePhotoView function from the observer of the crimeLiveData to make sure the photoView has already been initialized?