Android View Holder

ID

kotlin.android_view_holder

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

medium

Resource

Efficiency

Language

Kotlin

Tags

android, best-practice, efficiency

Description

Reports unconditional calls to inflate(…​) inside a getView(int, View, ViewGroup) override of an adapter subclass (BaseAdapter, ArrayAdapter, CursorAdapter).

Rationale

class BadAdapter : BaseAdapter() {
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val v = inflater.inflate(R.layout.row, parent, false)   // FLAW
        return v
    }
}

class GoodAdapter : BaseAdapter() {
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        if (convertView == null) {
            return inflater.inflate(R.layout.row, parent, false)
        }
        return convertView                                       // OK — reuse
    }
}

The ViewHolder pattern requires reusing the convertView parameter when it is non-null and inflating a new layout only when it is null. Unconditional inflation defeats view recycling and produces poor scrolling performance in list views.

Remediation

  • Guard the inflate(…​) call with if (convertView == null) and return the existing view otherwise.

  • Use the elvis operator: val v = convertView ?: inflater.inflate(…​).

  • Where possible, migrate to RecyclerView and the built-in ViewHolder lifecycle.