SpannableString可以序列化吗?

时间:2017-03-30 02:36:37

标签: java android serializable spannablestring

我想通过Intent发布一个带有SpannableString的对象。我让对象实现Serializable,但它会抛出

  

java.io.NotSerializableException:android.text.SpannableString

所以我让SpannableString实现Serializable。

private class MySpannableString extends SpannableString implements Serializable{
    public MySpannableString(CharSequence source) {
        super(source);
    }
}

但我无法在下一个活动中获得该对象。

5 个答案:

答案 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

DEMO

答案 1 :(得分:2)

根据SpannableString的文档,它没有实现Serializable接口,因此你得到了“java.io.NotSerializableException”异常。

文档 - https://developer.android.com/reference/android/text/SpannableString.html

通过扩展Sp​​annableString并实现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
    }
}

equalshashCode 实现来自 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?
}