"No hay suficiente información para inferir el parámetro T" con Kotlin y Android

110

Estoy tratando de replicar el siguiente ListView en mi aplicación de Android usando Kotlin: https://github.com/bidrohi/KotlinListView .

Lamentablemente, recibo un error que no puedo resolver por mí mismo. Aquí está mi código:

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
    }
}
}

Los diseños son exactamente como aquí: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

El mensaje de error completo que recibo es este: Error: (92, 31) Error en la inferencia de tipo: No hay suficiente información para inferir el parámetro T en fun findViewById (p0: Int): T! Especifíquelo explícitamente.

Agradecería cualquier ayuda que pueda conseguir.

Timo Güntner
fuente
2
Se puede tratar de cambiar this.label = ... as TextViewa this.label = row?.findViewById<TextView>, y hacerlo de manera análoga a val listView = ...? Hágame saber si esto funciona para que pueda hacer que esta sea una respuesta adecuada en ese caso.
Christian Brüggemann
1
¿Qué línea causa el error?
voddan
¿Puede demostrar el problema con un ejemplo más pequeño?
voddan
@ ChristianBrüggemann Así: i.imgur.com/ZeWKjt5.png y esto: i.imgur.com/Can7w0p.png ? Con sus ediciones, ahora hay estos errores: i.imgur.com/qqPAjrL.png
Timo Güntner
1
Pruebe esto this.label = row? .FindViewById <TextView> (R.id.label) como TextView
Alf Moh

Respuestas:

224

Debe utilizar API nivel 26 (o superior). Esta versión ha cambiado la firma de View.findViewById(): consulte aquí https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

Entonces, en su caso, donde el resultado de findViewByIdes ambiguo, debe proporcionar el tipo:

1 / Cambiar

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

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

2 / Cambiar

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

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

Tenga en cuenta que en 2 / la conversión solo es necesaria porque rowadmite nulos. Si label fuera anulable también, o si lo hizo rowno anulable, no sería obligatorio.

nmw
fuente
10
A continuación, se explica cómo resolver esto por lotes: Abra el cuadro de diálogo Reemplazar en ruta (Ctrl + Shift + R) y marque la casilla de expresiones regulares. Reemplazar findViewById\((.+?)\)\s+as\s+(.+)con findViewById<$2>\($1\)y ejecutar el reemplazo en todos los archivos. Resolvió casi todos mis errores.
Gustav Karlsson
1
¿Por qué es suficiente en Java inferir el tipo de vista de forma predeterminada y no es suficiente en Kotlin? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));esto está bien para Java.
uTha9
findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)funciona mejor para mí. Evita que algún código de una línea no haya terminado @GustavKarlsson
user3680200
1
El enlace no dice eso.
Alston
7

Andoid O cambiar la api findViewById de

vista pública findViewById (int id);

a

public T final findViewById (int id)

por lo tanto, si está dirigido a API 26, puede cambiar

val listView = findViewById (R.id.list) como ListView

a

val listView = findViewById (R.id.list)

o

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

Trinea
fuente
4

Esta funcionando

API de nivel 25 o inferior utilice este

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

API nivel 26 o superior utilice este

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

¡Feliz codificación!

Keshav Gera
fuente
2

Cambie su código a esto. Los lugares donde se produjeron los principales cambios están marcados con asteriscos.

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 }**
    }
}
Alf Moh
fuente
Si tiene como objetivo API 26 en su aplicación, la respuesta a continuación es la respuesta correcta. val listView = findViewById<ListView>(R.id.list)
EricWasTaken
@ericWasTaken Sí, tienes razón. Se supone que el compilador infiere el tipo a partir del contenido entre paréntesis. A veces falla en eso. Tu código también es correcto. Actualizaré mi respuesta para reflejar los cambios.
Alf Moh