在 Kotlin 中无法“findViewById”。收到错误“类型推断失败”

Posted

技术标签:

【中文标题】在 Kotlin 中无法“findViewById”。收到错误“类型推断失败”【英文标题】:Not able to "findViewById" in Kotlin. Getting error "Type inference failed" 【发布时间】:2017-12-10 13:10:53 【问题描述】:

当我尝试通过 id 查找 RecycleView 时出现以下错误。

错误:- 类型推断失败:没有足够的信息来推断参数 T

代码:

class FirstRecycleViewExample : AppCompatActivity() 
    val data = arrayListOf<String>()
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_recycleview)

        val recycler_view =  findViewById(R.id.recycler_view) as RecyclerView ///IN THIS LINE I AM GETTING THE ERROR

        data.add("First Data")
        data.add("Second Data")
        data.add("Third Data")
        data.add("Forth Data")
        data.add("Fifth Data")

        //creating our adapter
        val adapter = CustomRecycleAdapter(data)

        //now adding the adapter to recyclerview
        recycler_view.adapter = adapter
    

【问题讨论】:

【参考方案1】:

尝试类似:

val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)

您也可以使用Kotlin android Extensions。检查文档here。 有了它,你可以直接在你的代码中调用recycler_view

Kotlin Android 扩展:

在您的应用程序中gradle.build 添加apply plugin: 'kotlin-android-extensions' 在您的课程中添加 import kotlinx.android.synthetic.main.&lt;layout&gt;.* 的导入,其中 &lt;layout&gt; 是您的布局文件名。 就是这样,您可以直接在代码中调用recycler_view

它是如何工作的?第一次调用recycler_view 时,对findViewById 的调用完成并缓存

【讨论】:

在最新版本中,我收到警告要从 中删除类型。由于Android工作室强迫我在使用它时只使用钻石运算符&lt;&gt;,所以它给出了错误。【参考方案2】:

您处于 API 级别 26,其中 findViewById 的返回类型现在是通用的 T 而不是 View,因此可以推断。可以查看相关的更新日志here。

所以你应该能够做到这一点:

val recycler_view = findViewById<RecyclerView>(R.id.recycler_view)

或者这个:

val recycler_view: RecyclerView = findViewById(R.id.recycler_view)

【讨论】:

【参考方案3】:

已弃用

Kotlin 中,我们可以在不使用findViewById 语法的情况下获取视图的id。

例如,我们使用下面的布局,我们将获取视图的 id 并执行操作

布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_>

    <TextView
        android:id="@+id/welcomeMessage"
        android:layout_
        android:layout_
        android:layout_gravity="center"
        android:text="Hello World!"/>

</FrameLayout>

我们可以通过以下代码找到视图的id

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
 
    welcomeMessage.text = "Hello Kotlin!" ////WE ARE GETTING THE IDS WITHOUT USING THE FINDVIEWBYID syntax

怎么做?

为了能够使用它,您需要一个特殊的导入(我在下面写的那个),但 IDE 能够自动导入它。再简单不过了!

import kotlinx.android.synthetic.main.YOUR_LAYOUT_NAME.*/// HERE "YOUR_LAYOUT_NAME" IS YOUR LAYOUT NAME WHICH U HAVE INFLATED IN onCreate()/onCreateView() 

我们需要在不使用findviewbyid语法的情况下导入这个属性来获取视图的id。

有关此主题的更多信息,请参阅此链接:- Click here

更新

现在不推荐使用 kotlin-android-extensions ,而不是使用 kotlin 提供的绑定,我们现在可以使用 View-Binding 并且它的工作原理与上述解决方案相同,只是您需要使用在你的应用程序gradle下面

android 
    ...
    buildFeatures 
        viewBinding true
    

【讨论】:

绝妙的解决方案!帮了我很多! 使用这个解决方案有什么缺点吗?该解决方案看起来很棒,并且可以使代码更简洁。 @Ikdhruw 你也可以使用视图绑定,因为我已经更新了上面的解决方案【参考方案4】:

通常 Kotlin 可以使用括号中提供的信息推断您的类型。

在这种情况下,它不能,所以你必须像这样明确指定它

findViewById<RecyclerView>(R.id.recycler_view)

虽然不太确定类型,但你应该这样指定它

我想补充一点,使用Anko,您可以进一步简化您的代码,如下所示:

val recycler_view : RecyclerView =  find(R.id.recycler_view)

【讨论】:

【参考方案5】:

为您的代码添加这一行作为您使用的控制器。

val tvHello = findViewById<TextView>(R.id.tvHello)

【讨论】:

【参考方案6】:

您可以忽略在 kotlin 中为变量提供 id。你只需要使用一个插件

将其粘贴到您的 gradle 中

 apply plugin: 'kotlin-android-extensions'

然后你不需要为var分配id,你可以这样做

 recycler_view.setAdapter(youradapter);

【讨论】:

请提供拒绝投票的理由。【参考方案7】:

无法访问像 OP 一样的 ui 组件,在 app gradle 中需要如下所示:

plugins 
    ...
    id 'kotlin-android-extensions'

即使在添加此行之后,android studio 仍然无法自动解析 kotlin 合成的导入,因此您可能需要使缓存无效并重新启动。

如果仍然无法正常工作,请根据视图手动导入

活动/片段视图:导入 kotlinx.android.synthetic.main..* 普通视图: 导入 kotlinx.android.synthetic.main..view.*

更新 - 2

如果您收到此信息警告 -

警告:“kotlin-android-extensions”Gradle 插件已弃用。

插件“kotlin-android-extensions”将被弃用。 因此,在您的应用程序 gradle 中添加以下内容

android 
    ...
    buildFeatures 
        viewBinding true
    

【讨论】:

【参考方案8】:

试试这个:

这里bind 通用函数用于绑定视图。它的一般功能可以用于任何视图。

class MyActivity : AppCompatActivity() 
    private lateinit var recycler_view : RecyclerView
    override fun onCreate(savedInstanceState: Bundle?) 
        ...
        recycler_view = bind(R.id.recycler_view)
    


fun <T : View> Activity.bind(@IdRes res : Int) : T 
    @Suppress("UNCHECKED_CAST")    
    return findViewById(res) as T

【讨论】:

请为您的代码添加解释。不鼓励仅使用代码回答。 已添加。 @WilliMentzel【参考方案9】:

您甚至不必创建一个对象来使用视图执行操作。 你可以只使用id。例如, 科特林

recycle_view.adapter = adapter

等同于, Java

RecycleView recycle_view = (RecycleView) findViewById(recycle_view);
recycle_view.setAdapter(adapter);

【讨论】:

以上是关于在 Kotlin 中无法“findViewById”。收到错误“类型推断失败”的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin Android 视图绑定:findViewById vs Butterknife vs Kotlin Android Extension

Kotlin Android Extensions: 与 findViewById 说再见 (KAD 04) -- 更新版

Kotlin的android扩展:对findViewById说再见(KAD 04)

Android Kotlin findViewById(R.id.txt_email) 不能为空

kotlin-----代替findViewById的方法

将EditText数组转换为字符串数组 - Kotlin Android