我想通过Intent发布一个带有SpannableString的对象。我让对象实现Serializable,但它会抛出
java.io.NotSerializableException:android.text.SpannableString
所以我让SpannableString实现Serializable。
private class MySpannableString extends SpannableString implements Serializable{
public MySpannableString(CharSequence source) {
super(source);
}
}
但我无法在下一个活动中获得该对象。
答案 0 :(得分:3)
我已将SpannableString
传递为Serializable
,但它会在Can not cast Serializable to SpannableString, null value will return as default
等第二个活动中引发错误。所以我认为这可能是不可能的。
但是我们可以通过以下简单方式传递SpannableString
第一项活动
SpannableString text == ...;
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("KEY", text);
startActivity(intent);
第二项活动
SpannableString a = (SpannableString). getIntent().getCharSequenceExtra("KEY");
//we can get value because SpannableString implements CharSequence
答案 1 :(得分:2)
根据SpannableString的文档,它没有实现Serializable接口,因此你得到了“java.io.NotSerializableException”异常。
文档 - https://developer.android.com/reference/android/text/SpannableString.html
通过扩展SpannableString并实现Serializable接口来解决此问题的方法将无法正常工作。这样做的原因是,为了通过扩展它来使不可序列化的类可序列化,它需要具有可访问的无参数构造函数。 SpannableString类没有它,唯一可访问的构造函数将CharacterSequence作为参数。
根据Serializable接口的文档 -
“为了允许序列化非可序列化类的子类型,子类型可能负责保存和恢复超类型的public,protected和(如果可访问)包字段的状态。子类型可以假设这个只有当它扩展的类具有一个可访问的no-arg构造函数来初始化类的状态时才有责任。如果不是这种情况,则声明一个Serializable类是错误的。错误将在运行时被检测到。“ < / p>
文档 - https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
答案 2 :(得分:1)
我结合了 @Yarh 和 @kotoMJ 的答案,通过打包来将序列化值保持在最小大小:
class SerializedSpannableString(internal var value: SpannableString) : Serializable {
@Throws(IOException::class)
private fun writeObject(stream: ObjectOutputStream) {
val parcel = Parcel.obtain()
TextUtils.writeToParcel(value, parcel, 0)
stream.writeObject(parcel.marshall())
parcel.recycle()
}
@Throws(IOException::class, ClassNotFoundException::class)
private fun readObject(stream: ObjectInputStream) {
val byteArray: ByteArray = stream.readObject() as ByteArray
val parcel = Parcel.obtain()
parcel.unmarshall(byteArray, 0, byteArray.size)
parcel.setDataPosition(0)
value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel) as SpannableString
parcel.recycle()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as SerializedSpannableString
val thisSpans = value.getSpans(0, value.length, Any::class.java)
val otherSpans = other.value.getSpans(0, other.value.length, Any::class.java)
if (thisSpans.size != otherSpans.size) return false
return thisSpans.asSequence().zip(otherSpans.asSequence()).all { (thisSpan, otherSpan) ->
value.getSpanStart(thisSpan) == other.value.getSpanStart(otherSpan) &&
value.getSpanEnd(thisSpan) == other.value.getSpanEnd(otherSpan) &&
value.getSpanFlags(thisSpan) == other.value.getSpanFlags(otherSpan)
}
}
override fun hashCode(): Int {
var hash = value.toString().hashCode()
val spanCount = value.length
hash = hash * 31 + spanCount
value.getSpans(0, value.length, Any::class.java).forEach { span ->
hash = hash * 31 + value.getSpanStart(span)
hash = hash * 31 + value.getSpanEnd(span)
hash = hash * 31 + value.getSpanFlags(span)
}
return hash
}
}
equals
和 hashCode
实现来自 SpannableStringInternal
。
答案 3 :(得分:0)
您不能直接序列化它,但是可以使包装器将包装转换为HTML并序列化字符串。
class SpannableWp(var spannable: SpannableString? = null) : Serializable {
@Throws(IOException::class)
private fun writeObject(stream: ObjectOutputStream) {
stream.writeObject(spannable?.toHtml())
}
@Throws(IOException::class, ClassNotFoundException::class)
private fun readObject(stream: ObjectInputStream) {
val html = stream.readObject() as String
spannable = SpannableString(Html.fromHtml(html))
}
}
答案 4 :(得分:0)
我知道这不是直接回答您的问题。但是我正在解决类似的问题(使用导航组件时通过safeargs传递SpannableString),还有一个技巧如何为它制作可打包包装:
@Keep
class ParcelableSpanned2(
val spannableString: SpannableString?
) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readSpannableString())
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeSpannableString(spannableString, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<ParcelableSpanned2> {
override fun createFromParcel(parcel: Parcel): ParcelableSpanned2 {
return ParcelableSpanned2(parcel)
}
override fun newArray(size: Int): Array<ParcelableSpanned2?> {
return arrayOfNulls(size)
}
}
}
fun Parcel.writeSpannableString(spannableString: SpannableString?, flags: Int) {
TextUtils.writeToParcel(spannableString, this, flags)
}
fun Parcel.readSpannableString(): SpannableString? {
return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this) as SpannableString?
}