"Informazioni insufficienti per dedurre il parametro T" con Kotlin e Android


110

Sto cercando di replicare il seguente ListView nella mia app Android utilizzando Kotlin: https://github.com/bidrohi/KotlinListView .

Purtroppo ricevo un errore che non riesco a risolvere da solo. Ecco il mio codice:

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

I layout sono esattamente come qui: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

Il messaggio di errore completo che ricevo è questo: Errore: (92, 31) Inferenza del tipo non riuscita: informazioni insufficienti per dedurre il parametro T in fun findViewById (p0: Int): T! Si prega di specificarlo esplicitamente.

Apprezzerei tutto l'aiuto che posso ottenere.


2
Si può provare a cambiare this.label = ... as TextViewper this.label = row?.findViewById<TextView>e fare così analogamente per val listView = ...? Per favore fatemi sapere se funziona così posso renderlo una risposta adeguata in quel caso.
Christian Brüggemann

1
Quale linea causa l'errore?
voddan

Puoi dimostrare il problema con un esempio più piccolo?
voddan

@ ChristianBrüggemann In questo modo: i.imgur.com/ZeWKjt5.png e questo: i.imgur.com/Can7w0p.png ? Con le tue modifiche ora ci sono questi errori: i.imgur.com/qqPAjrL.png
Timo Güntner

1
Prova questo this.label = row? .FindViewById <TextView> (R.id.label) come TextView
Alf Moh

Risposte:


224

Devi utilizzare il livello API 26 (o superiore). Questa versione ha cambiato la firma di View.findViewById()- vedi qui https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

Quindi nel tuo caso, dove il risultato di findViewByIdè ambiguo, devi fornire il tipo:

1 / Modifica

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

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

2 / Cambia

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

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

Nota che in 2 / il cast è richiesto solo perché rowannulla. Se label fosse annullabile anche, o se rownon rendessi nullable, non sarebbe richiesto.


10
Ecco come risolverlo in batch: apri la finestra di dialogo Sostituisci nel percorso (Ctrl + Maiusc + R) e seleziona la casella regex. Sostituisci findViewById\((.+?)\)\s+as\s+(.+)con findViewById<$2>\($1\)ed esegui la sostituzione su tutti i file. Ha risolto quasi tutti i miei errori.
Gustav Karlsson

1
Perché è sufficiente in Java dedurre il tipo di visualizzazione per impostazione predefinita e non sufficiente in Kotlin? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));questo va bene per Java.
uTha9

findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)funziona meglio per me. Impedisce che il codice di una riga non finisca @GustavKarlsson
user3680200

1
Il collegamento non lo dice.
Alston

7

Andoid O cambia l'API findViewById da

public Visualizza findViewById (int id);

per

public final T findViewById (int id)

quindi, se hai come target l'API 26, puoi cambiare

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

per

val listView = findViewById (R.id.list)

o

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


4

Sta funzionando

Il livello API 25 o inferiore lo utilizza

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

Livello API 26 o superiore usa questo

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

Buona programmazione!


2

Cambia il tuo codice in questo. I punti in cui si sono verificati i principali cambiamenti sono contrassegnati da asterischi.

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

Se stai prendendo di mira l'API 26 nella tua app, la risposta di seguito è la risposta corretta. val listView = findViewById<ListView>(R.id.list)
EricWasTaken

@ericWasTaken Sì, hai ragione. Il compilatore dovrebbe dedurre il tipo dal contenuto tra parentesi. A volte fallisce in questo. Anche il tuo codice è corretto. Aggiornerò la mia risposta per riflettere le modifiche.
Alf Moh

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.