"Not enough information to infer parameter T" with Kotlin and Android

AndroidKotlinAndroid 8.0-Oreo

Android Problem Overview


I'm trying to replicate the following ListView in my Android app using Kotlin: https://github.com/bidrohi/KotlinListView.

Unfortunately I'm getting an error I'm unable to resolve myself. Here's my code:

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

    val listView = findViewById(R.id.list) as ListView
    listView.adapter = ListExampleAdapter(this)
}

private class ListExampleAdapter(context: Context) : BaseAdapter() {
    internal var sList = arrayOf("Eins", "Zwei", "Drei")
    private  val mInflator: LayoutInflater

    init {
        this.mInflator = LayoutInflater.from(context)
    }

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

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

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

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
        val view: View?
        val vh: ListRowHolder

        if(convertView == null) {
            view = this.mInflator.inflate(R.layout.list_row, parent, false)
            vh = ListRowHolder(view)
            view.tag = vh
        } else {
            view = convertView
            vh = view.tag as ListRowHolder
        }

        vh.label.text = sList[position]
        return view
    }
}

private class ListRowHolder(row: View?) {
    public val label: TextView

    init {
        this.label = row?.findViewById(R.id.label) as TextView
    }
}
}

The layouts are exactly as here: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

The full error message I'm getting is this: Error:(92, 31) Type inference failed: Not enough information to infer parameter T in fun findViewById(p0: Int): T! Please specify it explicitly.

I'd appreciate any help I can get.

Android Solutions


Solution 1 - Android

You must be using API level 26 (or above). This version has changed the signature of View.findViewById() - see here https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

So in your case, where the result of findViewById is ambiguous, you need to supply the type:

1/ Change

val listView = findViewById(R.id.list) as ListView to

val listView = findViewById<ListView>(R.id.list)

2/ Change

this.label = row?.findViewById(R.id.label) as TextView to

this.label = row?.findViewById<TextView>(R.id.label) as TextView

Note that in 2/ the cast is only required because row is nullable. If label was nullable too, or if you made row not nullable, it wouldn't be required.

Solution 2 - Android

Andoid O change findViewById api from

> public View findViewById(int id);

to

> public final T findViewById(int id)

so, if you are target to API 26, you can change

> val listView = findViewById(R.id.list) as ListView

to

> val listView = findViewById(R.id.list)

or

> val listView: ListView = findViewById(R.id.list)

Solution 3 - Android

Its Working

API Level 25 or below use this

    var et_user_name = findViewById(R.id.et_user_name) as EditText

API Level 26 or Above use this

    val et_user_name: EditText = findViewById(R.id.et_user_name)

Happy Coding !

Solution 4 - Android

Change your code to this. Where the main changes occurred are marked with asterisks.

package com.phenakit.tg.phenakit
 
import android.content.Context
import android.os.Bundle
import android.support.design.widget.BottomNavigationView
import android.support.v7.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import android.widget.TextView
 
public class MainActivity : AppCompatActivity() {
 
    private var mTextMessage: TextView? = null
 
    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
        when (item.itemId) {
            R.id.navigation_home -> {
                mTextMessage!!.setText(R.string.title_home)
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_dashboard -> {
                mTextMessage!!.setText(R.string.title_dashboard)
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_notifications -> {
                setContentView(R.layout.activity_list_view)
                return@OnNavigationItemSelectedListener true
            }
        }
        false
    }
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        mTextMessage = findViewById(R.id.message) as TextView?
        val navigation = findViewById(R.id.navigation) as BottomNavigationView
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
 
 
        **val listView = findViewById<ListView>(R.id.list)**
 
 
 
        **listView?.adapter = ListExampleAdapter(this)**
    }
 
    private class ListExampleAdapter(context: Context) : BaseAdapter() {
        internal var sList = arrayOf("Eins", "Zwei", "Drei")
        private  val mInflator: LayoutInflater
 
        init {
            this.mInflator = LayoutInflater.from(context)
        }
 
        override fun getCount(): Int {
            return sList.size
        }
 
        override fun getItem(position: Int): Any {
            return sList[position]
        }
 
        override fun getItemId(position: Int): Long {
            return position.toLong()
        }
 
        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
            val view: View?
            val vh: ListRowHolder
 
            if(convertView == null) {
                view = this.mInflator.inflate(R.layout.list_row, parent, false)
                vh = ListRowHolder(view)
                view.tag = vh
            } else {
                view = convertView
                vh = view.tag as ListRowHolder
            }
 
            vh.label.text = sList[position]
            return view
        }
    }
 
    private class ListRowHolder(row: View?) {
        public var label: TextView
 
        **init { this.label = row?.findViewById<TextView?>(R.id.label) as TextView }**
    }
}

Solution 5 - Android

I would suggest you to use synthetics kotlin Android extension:

https://kotlinlang.org/docs/tutorials/android-plugin.html

https://antonioleiva.com/kotlin-android-extensions/

In your case the code will be something like this:

init {
   this.label = row.label
}

As simple as that ;)

Solution 6 - Android

In android 12 remove as from your code and put your model in <> in front of getParcelableExtra.

change

intent.getParcelableExtra("MyModel") as MyModel

to

intent.getParcelableExtra `<MyModel>` ("MyModel")!!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimo G&#252;ntnerView Question on Stackoverflow
Solution 1 - AndroidnmwView Answer on Stackoverflow
Solution 2 - AndroidTrineaView Answer on Stackoverflow
Solution 3 - AndroidKeshav GeraView Answer on Stackoverflow
Solution 4 - AndroidAlf MohView Answer on Stackoverflow
Solution 5 - AndroidpauminkuView Answer on Stackoverflow
Solution 6 - AndroidAzade RahmatiView Answer on Stackoverflow