用Kotlin和Android,“没有足够的信息来推断参数T”。

148
我将使用Kotlin为Android应用程序复制以下ListView: 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 我收到的完整错误消息如下: Error:(92, 31) 类型推断失败:在 fun findViewById(p0: Int): T! 中没有足够的信息来推断参数 T,请明确指定。 如果您能提供任何帮助,我将不胜感激。

2
你能否尝试将 this.label = ... as TextView 更改为 this.label = row?.findViewById<TextView>,并对 val listView = ... 进行类似操作?如果可以,请告诉我,这样我就可以将其作为正确答案。 - Christian Brüggemann
1
哪一行导致了错误? - voddan
1
尝试这个:this.label = row?.findViewById<TextView>(R.id.label) as TextView - Alf Moh
@AlfMoh 在末尾加上问号(this.label = row?.findViewById<TextView>(R.id.label) as TextView?)后,我得到了以下错误:Error:(94, 26) 类型不匹配:推断类型为TextView?但是期望的是TextView。 - Timo Güntner
这个怎么样?public val label: TextView?init { this.label = row?.findViewById(R.id.label) as TextView? } - Alf Moh
显示剩余7条评论
7个回答

264

您必须使用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可为空时才需要进行类型转换。如果label也是可空的,或者如果您将row设置为非空,则不需要进行类型转换。


12
以下是批量解决此问题的方法:打开“替换路径”对话框(Ctrl+Shift+R),并勾选正则表达式框。将 findViewById\((.+?)\)\s+as\s+(.+) 替换为 findViewById<$2>\($1\),并在所有文件上运行替换。这几乎解决了我所有的错误。 - Gustav Karlsson
1
为什么在Java中默认推断视图类型就足够了,而在Kotlin中不够呢?findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: ")); 这在Java中是可以的。 - MainActivity
findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+) 对我来说更好。它可以防止一些单行代码不完整的情况。@GustavKarlsson - user3680200
1
链接上没有写那个。 - Alston

9

安卓 O 版本将 findViewById API 从

public View findViewById(int id);

更改为

public final T findViewById(int id)

所以,如果您的目标是 API 26,您可以将

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

更改为

val listView = findViewById(R.id.list)

或者

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


7

它正在工作

API Level 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)

编程愉快!


4

将你的代码改为以下内容。主要更改点用星号标记。

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
是的,你说得对。编译器应该从括号中的内容推断出类型。有时它会失败。你的代码也是正确的。我会更新我的答案以反映这些更改。 - Alf Moh

1

1
在 Android 12 中,需要将代码中的 as 关键字删除,并将你的 model 放在 <> 中放置在 getParcelableExtra 方法前面。
intent.getParcelableExtra("MyModel") as MyModel

为了

intent.getParcelableExtra `<MyModel>` ("MyModel")!!

0

在使用DataBindingUtil.setContentView(this,R.layout.activity_main)时,我遇到了这个错误。

出现错误的原因是这里应该返回与layout_main(充气布局)相关联的绑定,所以我通过以下方式解决了这个错误:

ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main)

所以,你的错误可能主要在于处理返回值。尝试设置并检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接