在Kotlin中无法使用“findViewById”,出现“类型推断失败”错误。

103

当我尝试通过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
    }
}
9个回答

140

试试这样做:

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

您可以使用 Kotlin Android扩展 来实现这一点。在此处查看文档
借助它,您可以直接在代码中调用 recycler_view

Kotlin Android扩展:

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

它是如何工作的?第一次调用recycler_view时,会执行对findViewById的调用并进行缓存。


在最新版本中,我收到了警告,要求从<>中删除Type。由于Android Studio强制我只使用钻石操作符<>,当我使用它时,它会出现错误。 - Asif Mushtaq

51

您现在的 API 版本是 26,在这个版本中,findViewById 的返回类型现在是通用的 T,而不是 View,因此可以被推断出来。您可以在这里查看相关的更改日志。

所以您应该能够这样做:

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

或者是这个:
val recycler_view: RecyclerView = findViewById(R.id.recycler_view)

21

已弃用

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

例如,我们正在使用以下布局,从中获取视图的id并执行操作

布局

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

    <TextView
        android:id="@+id/welcomeMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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。

有关此主题的更多信息,请参阅该链接:- 点击这里

更新

现在kotlin-android-extensions已弃用,取而代之的是使用kotlin提供的绑定,我们现在可以使用View-Binding,它与上述解决方案相同,只需在应用gradle中使用以下内容即可。

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

1
太棒了!帮了我很多忙! - gundrabur
1
使用此解决方案是否有任何缺点?该解决方案看起来非常棒,可以让代码更加清晰。 - lkdhruw
@Ikdhruw 你也可以使用视图绑定,因为我已经更新了上面的解决方案。 - Ravindra Kushwaha

8

通常情况下,Kotlin可以通过方括号中提供的信息推断出类型。

但在这种情况下,它无法推断出类型,因此您需要明确指定,如下所示:

findViewById<RecyclerView>(R.id.recycler_view)

我不太确定类型,但这就是你应该指定它的方式。

我想补充一下,使用Anko,你可以进一步简化你的代码,像这样:

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

7
在你正在使用的控制器中添加这行代码。
val tvHello = findViewById<TextView>(R.id.tvHello)

7

无法访问UI组件,类似OP遇到的问题如下,需要在应用gradle文件中添加以下内容:

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

尽管添加了这行代码,Android Studio 仍然无法自动解析 Kotlin Synthetics 的导入,因此您可能需要使缓存失效并重启应用程序。

如果仍然无法工作,则根据视图手动导入。

  • 活动/片段视图: 导入 kotlinx.android.synthetic.main.<your_activity_view>.*
  • 普通视图: 导入 kotlinx.android.synthetic.main.<your_layout_view>.view.*

更新-2

如果您收到以下信息警告-

Warning: The 'kotlin-android-extensions' Gradle plugin is deprecated.

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

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

5
你可以在Kotlin中忽略给变量命名ID。你只需要使用一个插件即可。
将以下代码粘贴到gradle中:
 apply plugin: 'kotlin-android-extensions'

然后您就不需要给变量分配id,可以像这样做:

 recycler_view.setAdapter(youradapter);

请提供一个下投票的理由。 - Anmol317
我在应用Kotlin 1.8.0时遇到了Gradle错误,导致项目无法运行。 - famfamfam

1

尝试这个:

这里使用 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
}

1
请在您的代码中添加解释。仅包含代码的答案是不鼓励的。 - Willi Mentzel
1
已添加。@WilliMentzel - Mehul Kabaria

1

您甚至不需要创建对象来操作视图。您可以直接使用ID。例如,Kotlin

recycle_view.adapter = adapter

等同于:

Java

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

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