“Não há informações suficientes para inferir o parâmetro T” com Kotlin e Android


110

Estou tentando replicar o seguinte ListView em meu aplicativo Android usando Kotlin: https://github.com/bidrohi/KotlinListView .

Infelizmente, estou recebendo um erro que não consigo resolver sozinho. Este é o meu 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
    }
}
}

Os layouts são exatamente como aqui: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

A mensagem de erro completa que estou recebendo é esta: Erro: (92, 31) Falha na inferência de tipo: Não há informações suficientes para inferir o parâmetro T em fun findViewById (p0: Int): T! Por favor, especifique explicitamente.

Agradeço qualquer ajuda que puder obter.


2
Você pode tentar mudar this.label = ... as TextViewpara this.label = row?.findViewById<TextView>e fazer isso de forma análoga para val listView = ...? Informe se isso funciona para que eu possa dar uma resposta adequada nesse caso.
Christian Brüggemann

1
Qual linha causa erro?
voddan

Você pode demonstrar o problema com um exemplo menor?
voddan

@ ChristianBrüggemann Assim: i.imgur.com/ZeWKjt5.png e este: i.imgur.com/Can7w0p.png ? Com suas edições, agora há estes erros: i.imgur.com/qqPAjrL.png
Timo Güntner

1
Tente this.label = row? .FindViewById <TextView> (R.id.label) como TextView
Alf Moh

Respostas:


224

Você deve usar a API de nível 26 (ou superior). Esta versão mudou a assinatura de View.findViewById()- veja aqui https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

Portanto, no seu caso, onde o resultado de findViewByIdé ambíguo, você precisa fornecer o tipo:

1 / mudança

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

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

2 / Mudar

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

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

Observe que em 2 / o elenco só é necessário porque rowé anulável. Se também label fosse anulável, ou se você tornasse rownão anulável, não seria necessário.


10
Veja como resolver isso em lote: Abra a caixa de diálogo Substituir no caminho (Ctrl + Shift + R) e marque a caixa regex. Substitua findViewById\((.+?)\)\s+as\s+(.+)por findViewById<$2>\($1\)e execute a substituição em todos os arquivos. Isso resolveu quase todos os meus erros.
Gustav Karlsson,

1
Por que é suficiente em Java inferir o tipo de visualização por padrão e não é suficiente em Kotlin? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));isso é bom para Java.
Serge

findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)funciona melhor para mim. Impede que o código de uma linha não termine @GustavKarlsson
user3680200

1
O link não diz isso.
Alston

7

Andoid O alterar api findViewById de

public Exibir findViewById (int id);

para

public final T findViewById (int id)

então, se você tem como alvo a API 26, você pode mudar

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

para

val listView = findViewById (R.id.list)

ou

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


4

Está funcionando

API de nível 25 ou inferior usa isso

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

API de nível 26 ou superior usa isso

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

Happy Coding!


2

Mude seu código para isso. Os locais onde ocorreram as principais alterações estão marcados com 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 }**
    }
}

Se você está direcionando a API 26 em seu aplicativo, a resposta abaixo é a resposta correta. val listView = findViewById<ListView>(R.id.list)
EricWasTaken

@ericWasTaken Sim, você está certo. O compilador deve inferir o tipo a partir do conteúdo entre colchetes. Às vezes falha nisso. Seu código também está correto. Atualizará minha resposta para refletir as mudanças.
Alf Moh

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.