Android中包含ImageButton的类实现Parcelable时的初始化问题
兄弟,你的问题核心在于ImageButton这类Android View对象根本不能被Parcel序列化,别再尝试用readAny()强转了,完全走不通的。原因很简单:View持有Context引用,还和Android的视图层级、生命周期深度绑定,Parcelable机制没办法正确保存和恢复它的完整状态,强行序列化甚至会导致内存泄漏。
给你两个可行的解决方案:
方案一:重构类,拆分数据与视图引用
这是最推荐的做法,把数据模型和视图实例彻底分开——你的T类应该只存纯数据,不要持有任何View对象。比如把ImageButton换成图片的资源ID(Int类型),这样序列化就完全没问题了。
修改后的完整代码示例:
import android.os.Parcel import android.os.Parcelable class T(val eyes: Int, val imageResId: Int) : Parcelable { var value = eyes var isPressed = false // Parcel构造器 constructor(parcel: Parcel) : this( parcel.readInt(), parcel.readInt() ) { value = parcel.readInt() isPressed = parcel.readByte() != 0.toByte() } override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(eyes) parcel.writeInt(imageResId) parcel.writeInt(value) parcel.writeByte(if (isPressed) 1 else 0) } override fun describeContents(): Int { return 0 } companion object CREATOR : Parcelable.Creator<T> { override fun createFromParcel(parcel: Parcel): T { return T(parcel) } override fun newArray(size: Int): Array<T?> { return arrayOfNulls(size) } } }
使用的时候,在你的Activity/Fragment里根据资源ID去设置ImageButton的内容:
// 创建T实例 val tItem = T(2, R.drawable.my_button_image) // 给已有的ImageButton设置图片 myImageButton.setImageResource(tItem.imageResId) // 如果需要恢复isPressed状态 myImageButton.isPressed = tItem.isPressed
方案二:如果必须保存View状态(不推荐)
如果你非要保存View的状态(比如isPressed),那应该让View自己处理状态保存,而不是放到Parcelable模型里。每个View都有onSaveInstanceState()和onRestoreInstanceState()方法,你可以重写这两个方法来保存View的状态:
class CustomImageButton(context: Context, attrs: AttributeSet) : ImageButton(context, attrs) { override fun onSaveInstanceState(): Parcelable? { val superState = super.onSaveInstanceState() val savedState = SavedState(superState) savedState.isPressed = isPressed return savedState } override fun onRestoreInstanceState(state: Parcelable?) { if (state !is SavedState) { super.onRestoreInstanceState(state) return } super.onRestoreInstanceState(state.superState) isPressed = state.isPressed } class SavedState(superState: Parcelable?) : BaseSavedState(superState) { var isPressed = false constructor(parcel: Parcel) : super(parcel) { isPressed = parcel.readByte() != 0.toByte() } override fun writeToParcel(parcel: Parcel, flags: Int) { super.writeToParcel(parcel, flags) parcel.writeByte(if (isPressed) 1 else 0) } companion object CREATOR : Parcelable.Creator<SavedState> { override fun createFromParcel(parcel: Parcel): SavedState { return SavedState(parcel) } override fun newArray(size: Int): Array<SavedState?> { return arrayOfNulls(size) } } } }
但还是要强调,这种方式只适合保存View自身的状态,不要把View实例放到你的Parcelable数据类里,这违背了MVC/MVVM的设计原则,也容易出问题。
内容的提问来源于stack exchange,提问作者mattssoncode
相关产品推荐
相关产品推荐

