在 Kotlin 中将 class 转换为它的子 class
Cast class to its subclass in Kotlin
我有一个名为 Opportunity 的 class 列表,其中充满了扩展 Opportunity 的对象。该列表可以包含 CommunityOpportunites 或 SponsorshipOpportunities。
我覆盖了 getItemViewType 并根据相关位置中的任何子对象为每个项目分配一个值class,并且每个项目都有不同的 ViewHolder:
override fun getItemViewType(position: Int): Int {
return if (opportunityList[position] is SponsorshipOpportunity){
Log.i(TAG,"Item type is sponsorshipId")
SPONSORSHIP
} else{
Log.i(TAG,"Item type is community")
COMMUNITY
}
}
inner class CommunityViewHolder(var view: CommunityTileBinding):RecyclerView.ViewHolder(view.root)
inner class SponsorshipViewHolder(var view: SponsorshipTileBinding):RecyclerView.ViewHolder(view.root)
companion object{
private const val COMMUNITY = 0
private const val SPONSORSHIP = 1
}
在 onCreateViewHolder() 中,我为项目的 class 创建了正确的 ViewHolder,在 onBindViewHolder() 中,我尝试将列表中的项目(构造函数中的机会类型)转换为子class 视图中的项目:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType){
COMMUNITY->CommunityViewHolder(DataBindingUtil.inflate(inflater, R.layout.community_tile, parent, false))
SPONSORSHIP-> SponsorshipViewHolder(DataBindingUtil.inflate(inflater, R.layout.sponsorship_tile, parent, false))
else-> throw IllegalArgumentException()
}
}
override fun getItemCount(): Int = opportunityList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder.itemViewType){
COMMUNITY-> {
(holder as CommunityViewHolder).view.communityOpportunity = opportunityList[position] as CommunityOpportunity
}
SPONSORSHIP->{
(holder as SponsorshipViewHolder).view.sponsorship = opportunityList[position] as SponsorshipOpportunity
holder.view.postActionText.text = context.resources.getString(R.string.watch_respond)
}
}
}
但是,我得到以下 class 转换异常
java.lang.ClassCastException: com.example.model.Opportunity cannot be cast to com.example.model.CommunityOpportunity
当我尝试在 onBindViewHolder 中的相关行时,即使打印了确认该项目是 getItemViewType() 中的 CommunityOpportunity 的日志语句。
有没有更好的方法来询问,或者有没有更好的方法让我在 RecyclerView 中显示多个 ViewHolder/Object 类型?
编辑:以下是相关的 xml 布局:
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="sponsorship"
type="com.example.weare8sample.model.SponsorshipOpportunity"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:elevation="2dp"
android:orientation="vertical"
android:background="@drawable/tile_background">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="@drawable/tile_background"
android:imageUrl="@{sponsorship.coverTileUri}">
</ImageView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:padding="10dp">
<TextView
android:id="@+id/postActionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/lato_bold"
tools:text="@string/watch_respond">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="@drawable/ic_chevron_right_black_36dp">
</ImageView>
</RelativeLayout>
</LinearLayout>
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="communityOpportunity"
type="com.example.weare8sample.model.CommunityOpportunity" />
</data>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/tile_background"
android:imageUrl="@{communityOpportunity.mediaImageUri}">
</ImageView>
为 getItemViewType
中的所有类型添加显式类型检查,如果是未知类型则抛出,以正确处理所有情况。
现在,如果有第三种类型的机会,它将被假定为 COMMUNITY
类型。
在您的模型中使用密封 class 是这种情况下的最佳选择
sealed class Opportunity {
data class CommunityOpportunites(
// class fields
):Opportunity()
data class SponsorshipOpportunities(
// class fields
):Opportunity()
}
并且在您的 getItemViewType 方法中应该是这样的
override fun getItemViewType(position: Int) = when (list[position]) {
is Opportunity.CommunityOpportunites-> 0
is Opportunity.SponsorshipOpportunities-> 1
}
和 onCreateViwHolder 方法
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
when (viewType) {
0 -> ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item1, parent,
false)
)
else->
LayoutInflater.from(parent.context).inflate(R.layout.item2, parent,
false)
)
}
你不必使用多个 ViwHolders 编写 ViewHolder inner class 像这样
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind() {
val d = list[adapterPosition]
when (d) {
is Opportunity.CommunityOpportunites -> {
itemView.apply {
//bind the data in the list to view you needn't cast d to
//CommunityOpportunites Kotlin smart cast does it for you
}
}
is Opportunity.SponsorshipOpportunities -> {
itemView.apply {
//bind the data in the list to view you needn't cast d to
//SponsorshipOpportunities Kotlin smart cast does it for you
}
}
}
}
}
我认为这应该有效:)
我有一个名为 Opportunity 的 class 列表,其中充满了扩展 Opportunity 的对象。该列表可以包含 CommunityOpportunites 或 SponsorshipOpportunities。
我覆盖了 getItemViewType 并根据相关位置中的任何子对象为每个项目分配一个值class,并且每个项目都有不同的 ViewHolder:
override fun getItemViewType(position: Int): Int {
return if (opportunityList[position] is SponsorshipOpportunity){
Log.i(TAG,"Item type is sponsorshipId")
SPONSORSHIP
} else{
Log.i(TAG,"Item type is community")
COMMUNITY
}
}
inner class CommunityViewHolder(var view: CommunityTileBinding):RecyclerView.ViewHolder(view.root)
inner class SponsorshipViewHolder(var view: SponsorshipTileBinding):RecyclerView.ViewHolder(view.root)
companion object{
private const val COMMUNITY = 0
private const val SPONSORSHIP = 1
}
在 onCreateViewHolder() 中,我为项目的 class 创建了正确的 ViewHolder,在 onBindViewHolder() 中,我尝试将列表中的项目(构造函数中的机会类型)转换为子class 视图中的项目:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType){
COMMUNITY->CommunityViewHolder(DataBindingUtil.inflate(inflater, R.layout.community_tile, parent, false))
SPONSORSHIP-> SponsorshipViewHolder(DataBindingUtil.inflate(inflater, R.layout.sponsorship_tile, parent, false))
else-> throw IllegalArgumentException()
}
}
override fun getItemCount(): Int = opportunityList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder.itemViewType){
COMMUNITY-> {
(holder as CommunityViewHolder).view.communityOpportunity = opportunityList[position] as CommunityOpportunity
}
SPONSORSHIP->{
(holder as SponsorshipViewHolder).view.sponsorship = opportunityList[position] as SponsorshipOpportunity
holder.view.postActionText.text = context.resources.getString(R.string.watch_respond)
}
}
}
但是,我得到以下 class 转换异常
java.lang.ClassCastException: com.example.model.Opportunity cannot be cast to com.example.model.CommunityOpportunity
当我尝试在 onBindViewHolder 中的相关行时,即使打印了确认该项目是 getItemViewType() 中的 CommunityOpportunity 的日志语句。
有没有更好的方法来询问,或者有没有更好的方法让我在 RecyclerView 中显示多个 ViewHolder/Object 类型?
编辑:以下是相关的 xml 布局:
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="sponsorship"
type="com.example.weare8sample.model.SponsorshipOpportunity"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:elevation="2dp"
android:orientation="vertical"
android:background="@drawable/tile_background">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="@drawable/tile_background"
android:imageUrl="@{sponsorship.coverTileUri}">
</ImageView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:padding="10dp">
<TextView
android:id="@+id/postActionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/lato_bold"
tools:text="@string/watch_respond">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="@drawable/ic_chevron_right_black_36dp">
</ImageView>
</RelativeLayout>
</LinearLayout>
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="communityOpportunity"
type="com.example.weare8sample.model.CommunityOpportunity" />
</data>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/tile_background"
android:imageUrl="@{communityOpportunity.mediaImageUri}">
</ImageView>
为 getItemViewType
中的所有类型添加显式类型检查,如果是未知类型则抛出,以正确处理所有情况。
现在,如果有第三种类型的机会,它将被假定为 COMMUNITY
类型。
在您的模型中使用密封 class 是这种情况下的最佳选择
sealed class Opportunity {
data class CommunityOpportunites(
// class fields
):Opportunity()
data class SponsorshipOpportunities(
// class fields
):Opportunity()
}
并且在您的 getItemViewType 方法中应该是这样的
override fun getItemViewType(position: Int) = when (list[position]) {
is Opportunity.CommunityOpportunites-> 0
is Opportunity.SponsorshipOpportunities-> 1
}
和 onCreateViwHolder 方法
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
when (viewType) {
0 -> ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item1, parent,
false)
)
else->
LayoutInflater.from(parent.context).inflate(R.layout.item2, parent,
false)
)
}
你不必使用多个 ViwHolders 编写 ViewHolder inner class 像这样
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind() {
val d = list[adapterPosition]
when (d) {
is Opportunity.CommunityOpportunites -> {
itemView.apply {
//bind the data in the list to view you needn't cast d to
//CommunityOpportunites Kotlin smart cast does it for you
}
}
is Opportunity.SponsorshipOpportunities -> {
itemView.apply {
//bind the data in the list to view you needn't cast d to
//SponsorshipOpportunities Kotlin smart cast does it for you
}
}
}
}
}
我认为这应该有效:)