Android Studio RecyclerView androidx.constraintlayout.widget.constraintlayout无法强制转换为Android.widget.TextView

Android Studio RecyclerView androidx.constraintlayout.widget.constraintlayout无法强制转换为Android.widget.TextView,android,kotlin,android-fragments,android-recyclerview,Android,Kotlin,Android Fragments,Android Recyclerview,我刚开始在Android Studio中使用Kotlin编程学习Android应用程序。当我想创建一个简单的RecyclerView示例时。我在使用recycler视图适配器时遇到错误 我在网上学习了一些教程,但是代码中仍然存在这个bug。我认为这个bug来自GameFragment.kt,它需要在其中设置布局管理器(下面是与初始化回收器视图相关的代码) 我试图打印日志消息以查看执行了哪个方法,结果显示适配器初始化了两次,onCreateViewHolder执行了一次,但onBindViewHo

我刚开始在Android Studio中使用Kotlin编程学习Android应用程序。当我想创建一个简单的RecyclerView示例时。我在使用recycler视图适配器时遇到错误

我在网上学习了一些教程,但是代码中仍然存在这个bug。我认为这个bug来自GameFragment.kt,它需要在其中设置布局管理器(下面是与初始化回收器视图相关的代码)

我试图打印日志消息以查看执行了哪个方法,结果显示适配器初始化了两次,onCreateViewHolder执行了一次,但onBindViewHolder从未执行过。 在LinearLayoutManager中,我试图将“this”、“activity”、“RequiredActivity”、“this作为上下文”、“activity.context”放在一起,但上述内容都不起作用。有人知道我如何解决这个问题吗


已生成错误日志

    java.lang.ClassCastException: androidx.constraintlayout.widget.ConstraintLayout cannot be cast to android.widget.TextView
        at com.jasonpwy.simplecountdowntimer.game.GameAdapter.onCreateViewHolder(GameAdapter.kt:31)
        at com.jasonpwy.simplecountdowntimer.game.GameAdapter.onCreateViewHolder(GameAdapter.kt:12)
        at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
        at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
        at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
        at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1855)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:530)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at com.android.internal.policy.DecorView.onLayout(DecorView.java:789)
        at android.view.View.layout(View.java:21946)
        at android.view.ViewGroup.layout(ViewGroup.java:6260)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3086)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2596)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1727)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7612)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1029)
        at android.view.Choreographer.doCallbacks(Choreographer.java:852)
        at android.view.Choreographer.doFrame(Choreographer.java:787)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1014)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:359)
        at android.app.ActivityThread.main(ActivityThread.java:7407)
game_fragment.xaml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="gameViewModel"
            type="com.example.simplecountdowntimer.game.GameViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraint_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <EditText
            android:id="@+id/activity_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:ems="10"
            android:hint="@string/activity_name"
            android:inputType="textPersonName"
            app:layout_constraintBaseline_toBaselineOf="@+id/timer_text"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent" />

        <Button
            android:id="@+id/submit_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="20dp"
            android:text="@string/submit"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/activity_name" />

        <TextView
            android:id="@+id/timer_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="32dp"
            android:layout_marginEnd="16dp"
            android:fontFamily="@font/roboto"
            android:text="@{gameViewModel.currentTimeString}"
            android:textSize="28sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/activity_name"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="16dp"
            android:layout_marginBottom="16dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/submit_btn"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
GameAdapter.kt

package com.jasonpwy.simplecountdowntimer.game

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.simplecountdowntimer.R

class GameAdapter() : RecyclerView.Adapter<GameAdapter.TextItemViewHolder>() {
    init{
        Log.i("Temp", "Created")
    }
    var data = listOf<String>()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
        val item = data[position]
        holder.view.text = item
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
        val textView = LayoutInflater.from(parent.context).inflate(R.layout.game_fragment, parent, false)
        return TextItemViewHolder(textView as TextView)
    }

    override fun getItemCount(): Int {
        return data.size
    }

    class TextItemViewHolder(val view: TextView): RecyclerView.ViewHolder(view)
}
package com.jasonpwy.simplecountdowntimer.game
导入android.util.Log
导入android.view.LayoutInflater
导入android.view.view
导入android.view.ViewGroup
导入android.widget.TextView
导入androidx.recyclerview.widget.recyclerview
导入com.example.simplecountdowntimer.R
类GameAdapter():RecyclerView.Adapter(){
初始化{
Log.i(“临时”、“已创建”)
}
var data=listOf()
设置(值){
字段=值
notifyDataSetChanged()
}
覆盖BindViewHolder(holder:TextItemViewHolder,位置:Int){
val项目=数据[位置]
holder.view.text=项目
}
重写CreateViewHolder(父级:ViewGroup,viewType:Int):TextItemViewHolder{
val textView=LayoutInflater.from(parent.context).充气(R.layout.game_片段,parent,false)
返回TextItemViewHolder(textView作为textView)
}
重写getItemCount():Int{
返回数据大小
}
类TextItemViewHolder(val视图:TextView):RecyclerView.ViewHolder(视图)
}
GameViewModel.kt

package com.example.simplecountdowntimer.game

import android.os.CountDownTimer
import android.text.format.DateUtils
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel

class GameViewModel : ViewModel(){
    companion object {

        // These represent different important times
        // This is when the game is over
        const val DONE = 0L
        // This is the number of milliseconds in a second
        const val ONE_SECOND = 1000L
        // This is the total time of the game
        const val COUNTDOWN_TIME = 10000L

    }

    private lateinit var timer : CountDownTimer
    private var _currentTime = MutableLiveData<Long>()
    val currentTime : LiveData<Long>
        get() = _currentTime

    val currentTimeString = Transformations.map(currentTime) { time ->
        DateUtils.formatElapsedTime(time)
    }

    private val _storedText = MutableLiveData<String>()
    val storeText : LiveData<String>
        get() = _storedText;

    private val _ListData = MutableLiveData<List<String>>()
    val ListData : LiveData<List<String>>
        get() = _ListData

    init{
        _storedText.value = ""
        _ListData.value = listOf()
        _ListData.value = _ListData.value?.plus("Testing only")
    }

    fun CountDown(){
        Log.i("Test", "Count Down Start")
        _currentTime.value = COUNTDOWN_TIME
        timer = object : CountDownTimer(COUNTDOWN_TIME, ONE_SECOND) {

            override fun onTick(millisUntilFinished: Long) {
                _currentTime.value = (millisUntilFinished/ONE_SECOND)
            }

            override fun onFinish() {
                _currentTime.value = DONE
            }
        }
        timer.start()
    }

    fun addText(message: String){
        _storedText.value += message
        _storedText.value += "\n"
        _storedText.value?.let { Log.i("Test", it) }
        _ListData.value = _ListData.value?.plus("Testing only")
    }
}
package com.example.simplecountdowntimer.game
导入android.os.CountDownTimer
导入android.text.format.DateUtils
导入android.util.Log
导入androidx.lifecycle.LiveData
导入androidx.lifecycle.MutableLiveData
导入androidx.lifecycle.Transformations
导入androidx.lifecycle.ViewModel
类GameViewModel:ViewModel(){
伴星{
//这些代表着不同的重要时期
//这是比赛结束的时候
const val DONE=0升
//这是每秒的毫秒数
常数值1秒=1000L
//这是比赛的总时间
常量值倒计时时间=10000L
}
私有lateinit变量计时器:倒计时
私有变量_currentTime=MutableLiveData()
val currentTime:LiveData
get()=\u当前时间
val currentTimeString=Transformations.map(currentTime){time->
DateUtils.formatElapsedTime(时间)
}
private val_storedText=MutableLiveData()
val storeText:LiveData
get()=\u storedText;
private val_ListData=MutableLiveData()
val ListData:LiveData
get()=\u ListData
初始化{
_storedText.value=“”
_ListData.value=listOf()
_ListData.value=_ListData.value?.plus(“仅测试”)
}
趣味倒数{
Log.i(“测试”,“倒计时开始”)
_currentTime.value=倒计时时间
定时器=对象:倒计时定时器(倒计时时间,1秒){
覆盖趣味点击(毫秒直到完成:长){
_currentTime.value=(毫秒到完成/1秒)
}
重写函数onFinish(){
_currentTime.value=完成
}
}
timer.start()
}
fun addText(消息:字符串){
_storedText.value+=消息
_storedText.value+=“\n”
_storedText.value?.let{Log.i(“Test”,it)}
_ListData.value=_ListData.value?.plus(“仅测试”)
}
}

您的错误消息是不言自明的。
TextView
不能转换为
ConstraintLayout

当您在
onCreateViewHolder
中展开视图时,会得到一个
视图
,它是正在展开的布局的根(
game\u fragment
),根是一个
ConstraintLayout
。因此,当您编写
返回TextItemViewHolder(textView作为textView)
时,会出现一个错误,因为
ConstraintLayout
不是
textView

您必须使用
findViewById
从膨胀的视图中获取
TextView
,类似于下面的代码

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.game_fragment, parent, false)
    val textView: TextView = view.findViewById(R.id.<id of your text view>)
    return TextItemViewHolder(textView as TextView)
}
重写CreateViewHolder(父级:ViewGroup,viewType:Int):TextItemViewHolder{
val view=LayoutInflater.from(parent.context).充气(R.layout.game_片段,parent,false)
val textView:textView=view.findViewById(R.id.)
返回TextItemViewHolder(textView作为textView)
}

我发现我误解了回收者观点的含义。我最终可以通过更改recycler视图适配器并向项目中添加一个布局来解决这个问题

我将项目上载到github:

recyclerview适配器的更新版本:

package com.example.simplecountdowntimer.game

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.jasonpwy.simplecountdowntimer.R
import kotlinx.android.synthetic.main.recyclerview_row.view.*

class TextItemViewHolder(view: View): RecyclerView.ViewHolder(view){
    var content: TextView = view.stored_message
}

class GameAdapter() : RecyclerView.Adapter<TextItemViewHolder>() {
    var data = listOf<String>()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
        val item = data[position]
        holder.content.text = item
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_row, parent, false)
        return TextItemViewHolder(view)
    }

    override fun getItemCount(): Int {
        return data.size
    }
}
package com.example.simplecountdowntimer.game
导入android.view.LayoutInflater
导入android.view.view
导入android.view.ViewGroup
导入android.widget.TextView
导入androidx.recyclerview.widget.recyclerview
导入com.jasonpwy.simplecountdowntimer.R
导入kotlinx.android.synthetic.main.recyclerview_row.view*
类TextItemViewHolder(视图:视图):RecyclerView.ViewHolder(视图){
变量内容:TextView=view.storaged\u消息
}
类GameAdapter():RecyclerView.Adapter(){
var data=listOf()
设置(值){
字段=值
notifyDataSetChanged()
}
推翻
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.game_fragment, parent, false)
    val textView: TextView = view.findViewById(R.id.<id of your text view>)
    return TextItemViewHolder(textView as TextView)
}
package com.example.simplecountdowntimer.game

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.jasonpwy.simplecountdowntimer.R
import kotlinx.android.synthetic.main.recyclerview_row.view.*

class TextItemViewHolder(view: View): RecyclerView.ViewHolder(view){
    var content: TextView = view.stored_message
}

class GameAdapter() : RecyclerView.Adapter<TextItemViewHolder>() {
    var data = listOf<String>()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
        val item = data[position]
        holder.content.text = item
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_row, parent, false)
        return TextItemViewHolder(view)
    }

    override fun getItemCount(): Int {
        return data.size
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp">

    <TextView
        android:id="@+id/stored_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        tools:text="Testing" />

</LinearLayout>