Kotlin ListView example | Android

In this Kotlin tutorial, we’re gonna look at way to show list of items with Android ListView.

Related Post: Kotlin GridView example: Show List of Items on Grid | Android

More Practice: Kotlin SQLite example – CRUD operations with ListView | Android

I. Technologies

– Android Studio 3
– Kotlin 1.1.51

II. Overview

1. Goal

We will build an Android App that uses ListView to show list of items:

kotlin-listview-goal

2. Android ListView

2.1 Input Types

Input (items) of a list can be arbitrary Kotlin object. We use an adapter to extract data from this Kotlin object, then assign object fields’value to the views in each row of ListView.

For example:


class Note {

    var id: Int? = null
    var title: String? = null
    var content: String? = null

    constructor(id: Int, title: String, content: String) {
        this.id = id
        this.title = title
        this.content = content
    }
}

Class for Kotlin object is called data model.

2.2 Adapter

Adapter (extends the BaseAdapter class) manages the data model and adapts it:


var notesAdapter = NotesAdapter(this, listNotes)
listviewNotes.adapter = notesAdapter


    class NotesAdapter : BaseAdapter {

        override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
            // inflate data model layout to View object
            // set value to View object
            return view
        }

        override fun getItem(position: Int): Any {
            // return item at 'position'
        }

        override fun getItemId(position: Int): Long {
            // return item Id by Long datatype
        }

        override fun getCount(): Int {
            // return quantity of the list
        }
    }

2.3 Listener

We can also set Listener for reacting to selections in the list. For example, handle onItemClick event:


listviewNotes.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, position, id ->
    // do something...
}

2.4 ViewHolder

ViewHolder allows to avoid the findViewById() method in adapter. It includes references to views in item layout.

BaseAdapter has getView() method that provide a convertView object, we can get the instance of the ViewHolder via the convertView.tag:


if (convertView == null) {
    view = layoutInflater.inflate(R.layout.note, parent, false)
    vh = ViewHolder(view)
    view.tag = vh
    Log.i("JSA", "set Tag for ViewHolder, position: " + position)
} else {
    view = convertView
    vh = view.tag as ViewHolder
}

// vh.tvTitle.text = title
// vh.tvContent.text = content

3. Project Structure

kotlin-listview-project-structure

III. Practice

1. Set up Project

– Create New Project:
kotlin-listview-create-project

– Add images (found in sourcecode) to drawable.

2. Layout

2.1 Main Activity

Open res/layout/activity_main.xml file, add ListView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/lvNotes"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

2.2 Item Layout

Add note.xml layout file to res/layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:padding="10dp"
    android:weightSum="10">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="9"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="Title"
            android:textColor="@color/colorPrimary"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/tvContent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="Text for Content" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/ivDelete"
            android:layout_width="30dp"
            android:layout_height="30dp"
            app:srcCompat="@drawable/ic_delete" />

        <ImageView
            android:id="@+id/ivEdit"
            android:layout_width="30dp"
            android:layout_height="30dp"
            app:srcCompat="@drawable/ic_edit" />
    </LinearLayout>
    
</LinearLayout>

3. Data Model

Add Kotlin class:


package com.javasampleapproach.kotlin.listview

class Note {

    var id: Int? = null
    var title: String? = null
    var content: String? = null

    constructor(id: Int, title: String, content: String) {
        this.id = id
        this.title = title
        this.content = content
    }

}

4. Activity

We will:
– create ViewHolder class
– create BaseAdapter subclass
– set adapter for ListView
– add Listener to ListView


package com.javasampleapproach.kotlin.listview

import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.BaseAdapter
import android.widget.TextView
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private var listNotes = ArrayList()

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

        listNotes.add(Note(1, "JavaSampleApproach", "Java technology, Spring Framework - approach to Java by Sample."))
        listNotes.add(Note(2, "Kotlin Android Tutorial", "Create tutorial for people to learn Kotlin Android. Kotlin is now an official language on Android. It's expressive, concise, and powerful. Best of all, it's interoperable with our existing Android languages and runtime."))
        listNotes.add(Note(3, "Android Studio", "Android Studio 3.0 provides helpful tools to help you start using Kotlin. Convert entire Java files or convert code snippets on the fly when you paste Java code into a Kotlin file."))
        listNotes.add(Note(4, "Java Android Tutorial", "Create tutorial for people to learn Java Android. Learn Java in a greatly improved learning environment with more lessons, real practice opportunity, and community support."))
        listNotes.add(Note(5, "Spring Boot Tutorial", "Spring Boot help build stand-alone, production Spring Applications easily, less configuration then rapidly start new projects."))

        var notesAdapter = NotesAdapter(this, listNotes)
        lvNotes.adapter = notesAdapter
        lvNotes.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, position, id ->
            Toast.makeText(this, "Click on " + listNotes[position].title, Toast.LENGTH_SHORT).show()
        }

    }

    inner class NotesAdapter : BaseAdapter {

        private var notesList = ArrayList()
        private var context: Context? = null

        constructor(context: Context, notesList: ArrayList) : super() {
            this.notesList = notesList
            this.context = context
        }

        override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {

            val view: View?
            val vh: ViewHolder

            if (convertView == null) {
                view = layoutInflater.inflate(R.layout.note, parent, false)
                vh = ViewHolder(view)
                view.tag = vh
                Log.i("JSA", "set Tag for ViewHolder, position: " + position)
            } else {
                view = convertView
                vh = view.tag as ViewHolder
            }

            vh.tvTitle.text = notesList[position].title
            vh.tvContent.text = notesList[position].content

            return view
        }

        override fun getItem(position: Int): Any {
            return notesList[position]
        }

        override fun getItemId(position: Int): Long {
            return position.toLong()
        }

        override fun getCount(): Int {
            return notesList.size
        }
    }

    private class ViewHolder(view: View?) {
        val tvTitle: TextView
        val tvContent: TextView

        init {
            this.tvTitle = view?.findViewById(R.id.tvTitle) as TextView
            this.tvContent = view?.findViewById(R.id.tvContent) as TextView
        }

        //  if you target API 26, you should change to:
//        init {
//            this.tvTitle = view?.findViewById(R.id.tvTitle) as TextView
//            this.tvContent = view?.findViewById(R.id.tvContent) as TextView
//        }
    }
}

IV. Source Code

Kotlin-ListView



By grokonez | December 6, 2017.

Last updated on April 14, 2021.



Related Posts


11 thoughts on “Kotlin ListView example | Android”

  1. I cannot explain why, but

    this.tvTitle = view?.findViewById(R.id.tvTitle) as TextView
    this.tvContent = view?.findViewById(R.id.tvContent) as TextView
    

    has to be changed to

    this.tvTitle = view?.findViewById(R.id.tvTitle) as TextView
    this.tvContent = view?.findViewById(R.id.tvContent) as TextView
    

    to get this thing running. Seems to be a change in the target API issue.
    I just adaptet some informations from here: https://stackoverflow.com/questions/45267041/not-enough-information-to-infer-parameter-t-with-kotlin-and-android

  2. sorry, has to be

    this.tvTitle = view?.findViewById<TextView>(R.id.tvTitle) as TextView
    this.tvContent = view?.findViewById<TextView>(R.id.tvContent) as TextView
    
  3. Hey JSA, this is a very useful tutorial. Exactly what I was looking for!
    I’m a novice programmer who’s very interested in Android Development (with Kotlin) but I find this a bit difficult to understand. I got your code to work with some extra work, but I am not 100% sure what every line does or why certain things are added in. Is there a possibility you can place a comment behind every line of newly introduced code explaining why you added that code?

    I feel like this would be incredibly useful to starting programmers, it’s one of the best ways to teach in my opinion. Looking forward to your response 🙂

    1. Hi karthik,

      import kotlinx.android.synthetic.main.activity_main.* helps us do this 🙂

      Regards,
      JSA.

    1. No, it sucks. Google is going to remove ListView and implemented RecycleView. and hundreds of elements they change in next coming every update. Not a good choice to work on Android development anymore

  4. Hello,

    nice turorial 🙂 But I´m getting an error, when I start the activity -> java.lang.RuntimeException: Unable to start activity ComponentInfo{de.company.listviews/de.company.listviews.ListView2}: java.lang.IllegalStateException: lvNotes must not be null

    Any ideas? I can´t find the problem. Why should my lvNotes be null? I also copied and pasted the code, to be sure it is the same. My target sdk version is 27, so I tryied both “init´s” in the ViewHolder.

    Thanks
    Best Regards

Got Something To Say:

Your email address will not be published. Required fields are marked *

*