«Недостаточно информации для вывода параметра T» с Kotlin и Android


111

Я пытаюсь воспроизвести следующий ListView в своем приложении для Android с помощью Kotlin: https://github.com/bidrohi/KotlinListView .

К сожалению, я получаю сообщение об ошибке, которое не могу решить самостоятельно. Вот мой код:

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

Макеты точно такие же, как здесь: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

Полное сообщение об ошибке, которое я получаю, выглядит так: Ошибка: (92, 31) Ошибка вывода типа: недостаточно информации для вывода параметра T в fun findViewById (p0: Int): T! Пожалуйста, укажите это явно.

Буду признателен за любую помощь, которую я могу получить.


2
Можете ли вы попробовать изменить this.label = ... as TextViewна this.label = row?.findViewById<TextView>и сделать это аналогично для val listView = ...? Пожалуйста, дайте мне знать, работает ли это, чтобы я мог дать правильный ответ в этом случае.
Christian Brüggemann

1
Какая строка вызывает ошибку?
voddan

Можете ли вы продемонстрировать проблему на небольшом примере?
voddan

@ ChristianBrüggemann Вот так : i.imgur.com/ZeWKjt5.png и это: i.imgur.com/Can7w0p.png ? С вашими правками теперь есть следующие ошибки: i.imgur.com/qqPAjrL.png
Timo Güntner

1
Попробуйте this.label = row? .FindViewById <TextView> (R.id.label) as TextView
Alf Moh

Ответы:


225

Вы должны использовать API уровня 26 (или выше). В этой версии была изменена подпись View.findViewById()- см. Здесь https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

Итак, в вашем случае, когда результат findViewByIdнеоднозначен, вам необходимо указать тип:

1 / Изменить

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

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

2 / Изменить

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

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

Обратите внимание, что в 2 / приведение требуется только потому, что rowдопускает значение NULL. Если label также допускалось rowзначение NULL, или если вы сделали его не допускающим значение NULL, это не потребовалось бы.


10
Вот как это разрешить пакетным способом: откройте диалоговое окно « Заменить в пути » (Ctrl + Shift + R) и установите флажок регулярного выражения. Заменить findViewById\((.+?)\)\s+as\s+(.+)на findViewById<$2>\($1\)и запустить замену для всех файлов. Он решил почти все мои ошибки.
Густав Карлссон

1
Почему в Java достаточно вывести тип представления по умолчанию, а в Котлине этого недостаточно? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));это нормально для Java.
uTha9

findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)у меня работает лучше. Это препятствует тому, чтобы какой-то однострочный код не закончился @GustavKarlsson
user3680200

1
Ссылка этого не говорит.
Alston

7

Andoid O изменить api findViewById с

общедоступный просмотр findViewById (int id);

к

общедоступный финал T findViewById (int id)

Итак, если вы нацелены на API 26, вы можете изменить

val listView = findViewById (R.id.list) как ListView

к

val listView = findViewById (R.id.list)

или

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


4

Это работает

Уровень API 25 или ниже используйте это

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

API уровня 26 или выше используйте это

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

Удачного кодирования!


2

Измените свой код на этот. Звездочками отмечены места, где произошли основные изменения.

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

Если вы ориентируетесь на API 26 в своем приложении, то приведенный ниже ответ будет правильным. val listView = findViewById<ListView>(R.id.list)
EricWasTaken

@ericWasTaken Да, вы правы. Предполагается, что компилятор определяет тип из содержимого в скобках. Иногда это не удается. Ваш код тоже правильный. Обновлю свой ответ, чтобы отразить изменения.
Альф Мох

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.