"Pas assez d'informations pour déduire le paramètre T" avec Kotlin et Android

111

J'essaie de reproduire le ListView suivant dans mon application Android à l'aide de Kotlin: https://github.com/bidrohi/KotlinListView .

Malheureusement, j'obtiens une erreur que je ne parviens pas à résoudre moi-même. Voici mon 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
    }
}
}

Les mises en page sont exactement comme ici: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

Le message d'erreur complet que j'obtiens est le suivant: Erreur: (92, 31) L'inférence de type a échoué: pas assez d'informations pour déduire le paramètre T dans le fun findViewById (p0: Int): T! Veuillez le spécifier explicitement.

J'apprécierais toute aide que je peux obtenir.

Timo Güntner
la source
2
Pouvez - vous essayer de changer this.label = ... as TextViewde this.label = row?.findViewById<TextView>et pour le faire de façon analogue val listView = ...? S'il vous plaît laissez-moi savoir si cela fonctionne afin que je puisse en faire une réponse appropriée dans ce cas.
Christian Brüggemann
1
Quelle ligne provoque une erreur?
voddan le
Pouvez-vous démontrer le problème avec un exemple plus petit?
voddan le
@ ChristianBrüggemann Comme ceci: i.imgur.com/ZeWKjt5.png et ceci: i.imgur.com/Can7w0p.png ? Avec vos modifications, il y a maintenant ces erreurs: i.imgur.com/qqPAjrL.png
Timo Güntner
1
Essayez ceci this.label = row? .FindViewById <TextView> (R.id.label) as TextView
Alf Moh

Réponses:

224

Vous devez utiliser le niveau d'API 26 (ou supérieur). Cette version a changé la signature de View.findViewById()- voir ici https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

Donc, dans votre cas, où le résultat de findViewByIdest ambigu, vous devez fournir le type:

1 / Changer

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

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

2 / Changer

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

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

Notez que dans 2 / le cast n'est requis que car il rowest nullable. Si label était également Nullable, ou si vous avez rendu rownon Nullable, cela ne serait pas obligatoire.

nmw
la source
10
Voici comment résoudre ce problème par lots: Ouvrez la boîte de dialogue Remplacer dans le chemin (Ctrl + Maj + R) et cochez la case regex. Remplacez findViewById\((.+?)\)\s+as\s+(.+)par findViewById<$2>\($1\)et exécutez le remplacement sur tous les fichiers. Cela a résolu presque toutes mes erreurs.
Gustav Karlsson
1
Pourquoi est-il suffisant en Java de déduire le type de vue par défaut et pas suffisant en Kotlin? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));c'est OK pour Java.
uTha9 du
findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)fonctionne mieux pour moi. Cela empêche que le code d'une ligne ne soit pas terminé @GustavKarlsson
user3680200
1
Le lien ne dit pas cela.
Alston
7

Andoid O changer l'API findViewById de

Vue publique findViewById (int id);

à

public final T findViewById (int id)

donc, si vous êtes cible de l'API 26, vous pouvez modifier

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

à

val listView = findViewById (R.id.list)

ou

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

Trinea
la source
4

Ça marche

API de niveau 25 ou inférieur à utiliser

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

API de niveau 26 ou supérieur à utiliser

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

Bon codage!

Keshav Gera
la source
2

Changez votre code pour cela. Les principaux changements sont signalés par des astérisques.

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
la source
Si vous ciblez l'API 26 dans votre application, la réponse ci-dessous est la bonne réponse. val listView = findViewById<ListView>(R.id.list)
EricWasTaken
@ericWasTaken Ouais, vous avez raison. Le compilateur est censé déduire le type à partir du contenu entre crochets. Parfois, cela échoue. Votre code est également correct. Mettra à jour ma réponse pour refléter les changements.
Alf Moh