"Nicht genug Informationen, um auf Parameter T zu schließen" mit Kotlin und Android

110

Ich versuche, die folgende ListView in meiner Android-App mit Kotlin zu replizieren: https://github.com/bidrohi/KotlinListView .

Leider erhalte ich einen Fehler, den ich nicht selbst beheben kann. Hier ist mein 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
    }
}
}

Die Layouts sind genau wie hier: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

Die vollständige Fehlermeldung, die ich erhalte, lautet wie folgt: Fehler: (92, 31) Typinferenz fehlgeschlagen: Nicht genügend Informationen, um Parameter T im Spaß abzuleiten findViewById (p0: Int): T! Bitte geben Sie dies ausdrücklich an.

Ich würde mich über jede Hilfe freuen, die ich bekommen kann.

Timo Güntner
quelle
2
Können Sie versuchen, this.label = ... as TextViewzu this.label = row?.findViewById<TextView>und analog zu wechseln val listView = ...? Bitte lassen Sie mich wissen, ob dies funktioniert, damit ich in diesem Fall eine richtige Antwort geben kann.
Christian Brüggemann
1
Welche Zeile verursacht Fehler?
Voddan
Können Sie das Problem anhand eines kleineren Beispiels demonstrieren?
Voddan
@ ChristianBrüggemann Gefällt mir : i.imgur.com/ZeWKjt5.png und dies: i.imgur.com/Can7w0p.png ? Mit Ihren Änderungen gibt es jetzt diese Fehler: i.imgur.com/qqPAjrL.png
Timo Güntner
1
Versuchen Sie dies this.label = row? .FindViewById <TextView> (R.id.label) als TextView
Alf Moh

Antworten:

224

Sie müssen API Level 26 (oder höher) verwenden. Diese Version hat die Signatur von geändert View.findViewById()- siehe hier https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

In Ihrem Fall, in dem das Ergebnis von nicht findViewByIdeindeutig ist, müssen Sie den Typ angeben:

1 / Ändern

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

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

2 / Ändern

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

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

Beachten Sie, dass in 2 / die Besetzung nur erforderlich ist, weil sie rownullbar ist. Wenn label es auch nullbar wäre oder wenn Sie es rownicht nullbar gemacht hätten, wäre es nicht erforderlich.

nmw
quelle
10
So beheben Sie das Problem im Stapel: Öffnen Sie das Dialogfeld " Im Pfad ersetzen " (Strg + Umschalt + R) und aktivieren Sie das Kontrollkästchen "Regex". Ersetzen findViewById\((.+?)\)\s+as\s+(.+)durch findViewById<$2>\($1\)und führen Sie das Ersetzen für alle Dateien aus. Es hat fast alle meine Fehler gelöst.
Gustav Karlsson
1
Warum ist es in Java ausreichend, standardmäßig auf den Ansichtstyp zu schließen, und in Kotlin nicht ausreichend? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));Dies ist in Ordnung für Java.
Serge
findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)funktioniert besser für mich. Es verhindert, dass ein einzeiliger Code nicht über @GustavKarlsson
user3680200
1
Der Link sagt das nicht.
Alston
7

Andoid O ändere findViewById API von

public View findViewById (int id);

zu

public final T findViewById (int id)

Wenn Sie also auf API 26 abzielen, können Sie Änderungen vornehmen

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

zu

val listView = findViewById (R.id.list)

oder

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

Trinea
quelle
4

Es funktioniert

API Level 25 oder niedriger verwenden dies

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

API Level 26 oder höher verwenden dies

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

Viel Spaß beim Codieren!

Keshav Gera
quelle
2

Ändern Sie Ihren Code in diesen. Wo die Hauptänderungen aufgetreten sind, sind mit Sternchen markiert.

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
quelle
Wenn Sie in Ihrer App auf API 26 abzielen, ist die folgende Antwort die richtige. val listView = findViewById<ListView>(R.id.list)
EricWasTaken
@ericWasTaken Ja, du hast recht. Der Compiler soll den Typ aus dem Inhalt in den Klammern ableiten. Manchmal scheitert es dabei. Ihr Code ist auch korrekt. Aktualisiert meine Antwort, um die Änderungen widerzuspiegeln.
Alf Moh