Open menu with table of contents Android Lists
Logo of Stuttgart Media University for light theme Logo of Stuttgart Media University for dark theme
Android Development

Android Lists

Stuttgart Media University

1 Agenda

  • RecyclerView the old way
  • Lazy lists the new way
  • Assignment 2

2 RecyclerView

  • It's the old way to show items in a scrollable list
  • The items are defined by an Adapter which is also responsible for the layout and rendering of the items in the list
  • Each item is selectable
  • Replaces old ListView
  • Solves performance bottleneck by forcing developers to implement ViewHolder pattern
  • Can be used to display
    • List
    • Grid
    • Pager
  • LayoutManager defines direction
    • vertical
    • horizontal
  • Highly customizable

40%

3 RecyclerView Full Example

  • The RecyclerView delegates the presentation of items to the corresponding Adapter
  • The Android Framework already provides us with implementations of the Adapter interface

3.1 Activity Layout

<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main3.xml -->
<androidx.recyclerview.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

3.2 List Item Layout

<?xml version="1.0" encoding="utf-8"?>
<!-- list_item_view.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/item_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/item_number" />
</androidx.constraintlayout.widget.ConstraintLayout>

3.3 Activity Class

  • Forces you to implement ViewHolder
  • Creates view holders as needed
  • Describes an item view and metadata about its place within the RecyclerView
  • Lets the Adapter cache expensive View.findViewById(int) results
  • Will be created and reused by RecyclerView.Adapter
package de.hdmstuttgart.manifestdemo;

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity(), MovieClickListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val recyclerView = findViewById<RecyclerView>(R.id.list)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))

        val list: MutableList<DummyItem> = ArrayList<DummyItem>()
        for (i in 0..100) {
            list.add(DummyItem(i.toString(), " - "))
        }

        val adapter = MovieAdapter(data)
        recyclerView.adapter = adapter
    }

    class DummyItem(var id: String, var content: String)

    class MovieAdapter(private val list: List<DummyItem>, private val movieClickListener: MovieClickListener): RecyclerView.Adapter<MovieAdapter.ViewHolder>() {

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {

            val view = LayoutInflater.from(parent.context).inflate(R.layout.movie_view, parent, false)
            return ViewHolder(view)
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val dummyItemModel = list[position]
            holder.itemNumberView.text = dummyItemModel.id
            holder.contentView.text = dummyItemModel.content
        }

        override fun getItemCount(): Int {
            return list.size
        }

        class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
            val itemNumberView: TextView = itemView.findViewById(R.id.item_number)
            val contentView: TextView = itemView.findViewById(R.id.content)
        }
    }
}

4 Lazy lists

  • LazyColumn and LazyRow follows the same patterns as RecyclerView but makes it much easier in Jetpack Compose
  • Lazy components are different compared to regular @Composable. They provide a LazyListScope block in order to describe the item contents.

Check the following example:

@Composable
fun MovieList(modifier: Modifier = Modifier) {
    val movieList = remember {
        mutableStateListOf<Movie>(
            //Movie objects
        )
    }
    
    LazyColumn(modifier = modifier) {
        items(items = movieList) { movie: Movie ->
            MovieItem(movie = movie, onMovieClick = { currentMovie: Movie ->
                movieList.remove(currentMovie)
            })
        }
    }
}

5 Android Assignment 2

Questions?