Android Studio RecyclerView androidx.constraintlayout.widget.constraintlayout无法强制转换为Android.widget.TextView
我刚开始在Android Studio中使用Kotlin编程学习Android应用程序。当我想创建一个简单的RecyclerView示例时。我在使用recycler视图适配器时遇到错误 我在网上学习了一些教程,但是代码中仍然存在这个bug。我认为这个bug来自GameFragment.kt,它需要在其中设置布局管理器(下面是与初始化回收器视图相关的代码) 我试图打印日志消息以查看执行了哪个方法,结果显示适配器初始化了两次,onCreateViewHolder执行了一次,但onBindViewHolder从未执行过。 在LinearLayoutManager中,我试图将“this”、“activity”、“RequiredActivity”、“this作为上下文”、“activity.context”放在一起,但上述内容都不起作用。有人知道我如何解决这个问题吗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
已生成错误日志
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>