Android RecyclerView Tutorial with Kotlin

In this Android RecyclerView tutorial, learn how to use Kotlin to display datasets of a large or unknown size! By Kevin D Moore.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Hooking up the Adapter and RecyclerView

This is the moment you’ve been waiting for. Connect your adapter to your RecyclerView and make sure it retrieves photos when created so you can explore outer space — in pictures.

Open MainActivity.kt, and add this property at the top:

private lateinit var adapter: RecyclerAdapter

Next, underneath the assignment of recyclerView.layoutManager, add the following:

adapter = RecyclerAdapter(photosList)
recyclerView.adapter = adapter

Here you’re creating the adapter, passing in the constructors it needs and setting it as the adapter for your RecyclerView.

Although you connected the adapter, there’s one more thing to do to make sure you don’t have an empty screen.

In onStart(), underneath the call to super, add this code:

if (photosList.size == 0) {
  requestPhoto()
}

This adds a check to see if your list is empty, and if yes, it requests a photo.

Next, in receivedNewPhoto(), add the following after photosList.add:

    adapter.notifyItemInserted(photosList.size-1)

So it looks like the following:

override fun receivedNewPhoto(newPhoto: Photo) {
  runOnUiThread {
    photosList.add(newPhoto)
    adapter.notifyItemInserted(photosList.size-1)
  }
}

Here, you inform the recycler adapter that you added an item after updating the list of photos.

Run the app, load up the emulator and before long, Galacticon should look something like this:

7. RecyclerView Working

That’s not all. Tap on the photo, and you should see a new activity that brings that item into focus:

8. Focus Activity

That’s still not all! Try rotating your device or emulator (Function-Control-F11 or F12) and you’ll see the image in full screen glory!

9. Landscape focus

Depending on the size of the image and your device screen it may look a little distorted, but don’t worry about that.

Congratulations! You have a working RecyclerView. Take a journey amongst the stars!

Adding Scrolling Support

If you head back to MainActivity on your device and try to scroll down, you’ll notice something is amiss — your RecyclerView isn’t retrieving any new photos.

10. Scrolling Not Working

Your RecyclerView is doing as it’s told by showing the contents of photosList. The problem is the app will only retrieve one photo. It has no idea when or how to grab more.

To remedy this, retrieve the number of the photos and the last visible photo index while scrolling. Then you’ll check to see that the last photo is visible and there are no photos already on request. If these are both true, then your app downloads more pretty photos!

This patch will require a spacewalk, so break out your spacesuit and get ready for a zero-gravity experience.

In MainActivity.kt, add this property with custom accessor below to MainActivity:

private val lastVisibleItemPosition: Int
  get() = linearLayoutManager.findLastVisibleItemPosition()

This uses your RecyclerView’s LinearLayoutManager to get the index of the last visible item on the screen.

Next, add a method inside of MainActivity that inserts an onScrollListener to your RecyclerView, so it can get a callback when the user scrolls:

  private fun setRecyclerViewScrollListener() {
    recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
      override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        super.onScrollStateChanged(recyclerView, newState)
        val totalItemCount = recyclerView.layoutManager!!.itemCount
        if (!imageRequester.isLoadingData && totalItemCount == lastVisibleItemPosition + 1) {
          requestPhoto()
        }
      }
    })
  }

This function gives the RecyclerView a scroll listener triggered by scrolling. While scrolling, the listener retrieves the count of the items in its LayoutManager and calculates the last visible photo index. Once done, it compares these numbers, incrementing the index by one because the index begins at zero while the count begins at one. If they match and there are no photos already on request, you request a new photo.

Finally, hook everything to the RecyclerView by calling this method from onCreate beneath where you set your RecyclerView Adapter:

setRecyclerViewScrollListener()

Build and run the app again. Scroll down, and you should see quite an improvement!

11. Scrolling Update

Excellent work! Your RecyclerView now updates to show the latest photo requested by your app. The great thing is that receivedNewPhoto() handles most of the work because you told it to notify your adapter about new items.

That earns an intergalactic thumbs up for upcycling code!

Layout Changes

Now that your RecyclerView is up and running, it’s time to trick out your spaceship.

Wouldn’t it be cool if your RecyclerView could change its layout? Good news: RecyclerView’s item positioning is separated into a layout manager.

Add a property for a GridLayoutManager to the top of MainActivity.kt:

private lateinit var gridLayoutManager: GridLayoutManager

Note that GridLayoutManager is built-in, but you can easily customize it.

In onCreate(), initialize the LayoutManager below the existing LinearLayoutManager:

gridLayoutManager = GridLayoutManager(this, 2)

As with the previous LayoutManager, pass in the context the manager will appear in. Unlike the former, it takes an integer parameter. In this case, set the number of columns the grid will have.

Add this method to MainActivity:

private fun changeLayoutManager() {
  if (recyclerView.layoutManager == linearLayoutManager) {
    //1
    recyclerView.layoutManager = gridLayoutManager
    //2
    if (photosList.size == 1) {
      requestPhoto()
    }
  } else {
    //3
    recyclerView.layoutManager = linearLayoutManager
  }
}

This code checks to see what LayoutManager your RecyclerView is using, and then:

  1. If it’s using the LinearLayoutManager, it swaps in the GridLayoutManager.
  2. It requests a new photo if your grid layout only has one photo to show.
  3. If it’s using the GridLayoutManager, it swaps in the LinearLayoutManager.

Next, make some changes to lastVisibleItemPosition to help it handle the new LayoutManager. Make it look like the following:

private val lastVisibleItemPosition: Int
  get() = if (recyclerView.layoutManager == linearLayoutManager) {
      linearLayoutManager.findLastVisibleItemPosition()
    } else {
      gridLayoutManager.findLastVisibleItemPosition()
    }

Here, you ask the RecyclerView to tell you what its LayoutManager is. Then you ask that LayoutManager to tell you the position of the last visible item.

To use the grid layout, make use of the Options menu button that is already available in the app. Add the following code underneath onStart():

override fun onOptionsItemSelected(item: MenuItem): Boolean {
  if (item.itemId == R.id.action_change_recycler_manager) {
    changeLayoutManager()
    return true
  }
  return super.onOptionsItemSelected(item)
}

This checks the ID of the item tapped in the menu and then determines what to do about it. In this case, there should only be one ID that will match up, effectively telling the app to go away and rearrange the RecyclerView’s LayoutManager.

You’re ready to go! Load the app and tap the button at the top right of the screen. You’ll begin to see the stars shift:

12. Grid Layout