致命信号 11 (SIGSEGV),代码 128,使用 Gson.fromJson 时 tid 12680 中的故障地址 0x0

Fatal signal 11 (SIGSEGV), code 128, fault addr 0x0 in tid 12680 when using Gson.fromJson

我的应用程序崩溃时除了出现此错误外没有任何堆栈跟踪:

A/libc: Fatal signal 11 (SIGSEGV), code 128, fault addr 0x0 in tid 12680 (dio.downloadapp)

经过一些故障排除后,我将其缩小到导致此错误的这一行:

val details = gson.fromJson(fileReader, VideoDetails::class.java)

它来自视图模型的方法:

private fun onVideoDetailsFetched() {
            try {
                val file = File(context.filesDir, QUEUE_VIDEO_DETAILS_FILE)
                val fileReader = FileReader(file)
                val details = gson.fromJson(fileReader, VideoDetails::class.java)
                videoDetails.send(details)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

该文件是在 WorkManager 库的 Worker class 方法中创建的:

    private fun VideoDetails.saveVideoDetails() {
        val json = gson.toJson(this)
        File(applicationContext.filesDir, VIDEO_DETAILS_FILE).writeText(json)
    }

此外VideoDetails只是一个数据class,带有一堆字符串和一个位图:

data class VideoDetails(
        val filename: String? = null,
        val title: String? = null,
        val vcodec: String? = null,
        val acodec: String? = null,
        val duration: String? = null,
        val filesize: String? = null,
        val width: String? = null,
        val height: String? = null,
        val bitrate: String? = null,
        val framerate: String? = null,
        val encoder: String? = null,
        val encodedBy: String? = null,
        val date: String? = null,
        val creationTime: String? = null,
        val artist: String? = null,
        val album: String? = null,
        val albumArtist: String? = null,
        val track: String? = null,
        val genre: String? = null,
        val composer: String? = null,
        val performer: String? = null,
        val copyright: String? = null,
        val publisher: String? = null,
        val language: String? = null,
        var thumbnail: Bitmap? = null
)

奇怪的是,只有当 Gson.fromJson() 第三次调用时才会发生崩溃。前两次,它工作正常。

有人知道我为什么会收到此错误吗?以及如何解决?

更新:

当我删除位图时它看起来有效。现在,问题是如何存储位图并使其工作。

根本原因是VideoDetails数据class中的位图。显然,Gson 不能处理位图。我没有删除位图,而是决定为 VideoDetails 创建自定义 TypeAdapter。这样我就不必更改 VideoDetails class 因此,我不必更改代码的许多部分。

完整代码:

class VideoDetailsTypeAdapter : TypeAdapter<VideoDetails?>() {
    override fun write(out: JsonWriter?, value: VideoDetails?) {
        value?.apply {
            out?.apply {
                beginObject()
                filename?.let { name(FILENAME).value(it) }
                title?.let { name(TITLE).value(it) }
                vcodec?.let { name(VCODEC).value(it) }
                acodec?.let { name(ACODEC).value(it) }
                duration?.let { name(DURATION).value(it) }
                filesize?.let { name(FILESIZE).value(it) }
                width?.let { name(WIDTH).value(it) }
                height?.let { name(HEIGHT).value(it) }
                bitrate?.let { name(BITRATE).value(it) }
                framerate?.let { name(FRAMERATE).value(it) }
                encoder?.let { name(ENCODER).value(it) }
                encodedBy?.let { name(ENCODED_BY).value(it) }
                date?.let { name(DATE).value(it) }
                creationTime?.let { name(CREATION_TIME).value(it) }
                artist?.let { name(ARTIST).value(it) }
                album?.let { name(ALBUM).value(it) }
                albumArtist?.let { name(ALBUM_ARTIST).value(it) }
                track?.let { name(TRACK).value(it) }
                genre?.let { name(GENRE).value(it) }
                composer?.let { name(COMPOSER).value(it) }
                performer?.let { name(PERFORMER).value(it) }
                copyright?.let { name(COPYRIGHT).value(it) }
                publisher?.let { name(PUBLISHER).value(it) }
                language?.let { name(LANGUAGE).value(it) }
                thumbnail?.let {
                    name(THUMBNAIL).beginArray()
                    val pixelInts = IntArray(it.width * it.height)
                    it.getPixels(pixelInts, 0, it.width, 0, 0, it.width, it.height)
                    val storeInts = IntArray(pixelInts.size + 2)
                    pixelInts.copyInto(storeInts, 0, 0, pixelInts.size)
                    storeInts[storeInts.size - 2] = it.width
                    storeInts[storeInts.size - 1] = it.height
                    for (int in storeInts)
                        value(int)
                    endArray()
                }
                endObject()
            }
        }
    }

    override fun read(`in`: JsonReader?): VideoDetails? {
        return `in`?.run {
            beginObject()
            val entries = Array<String?>(24) { null }
            var thumbnail: Bitmap? = null
            while (hasNext()) {
                when (nextName()) {
                    FILENAME -> entries[0] = nextString()
                    TITLE -> entries[1] = nextString()
                    VCODEC -> entries[2] = nextString()
                    ACODEC -> entries[3] = nextString()
                    DURATION -> entries[4] = nextString()
                    FILESIZE -> entries[5] = nextString()
                    WIDTH -> entries[6] = nextString()
                    HEIGHT -> entries[7] = nextString()
                    BITRATE -> entries[8] = nextString()
                    FRAMERATE -> entries[9] = nextString()
                    ENCODER -> entries[10] = nextString()
                    ENCODED_BY -> entries[11] = nextString()
                    DATE -> entries[12] = nextString()
                    CREATION_TIME -> entries[13] = nextString()
                    ARTIST -> entries[14] = nextString()
                    ALBUM -> entries[15] = nextString()
                    ALBUM_ARTIST -> entries[16] = nextString()
                    TRACK -> entries[17] = nextString()
                    GENRE -> entries[18] = nextString()
                    COMPOSER -> entries[19] = nextString()
                    PERFORMER -> entries[20] = nextString()
                    COPYRIGHT -> entries[21] = nextString()
                    PUBLISHER -> entries[22] = nextString()
                    LANGUAGE -> entries[23] = nextString()
                    THUMBNAIL -> {
                        beginArray()
                        val intList = mutableListOf<Int>()
                        while (hasNext())
                            intList.add(nextInt())
                        endArray()
                        val storeInts = intList.toIntArray()
                        val pixelInts = IntArray(storeInts.size - 2)
                        storeInts.copyInto(pixelInts, 0, 0, storeInts.size - 2)
                        val width = storeInts[storeInts.size - 2]
                        val height = storeInts[storeInts.size - 1]
                        thumbnail = Bitmap.createBitmap(pixelInts, width, height, Bitmap.Config.ARGB_8888)
                    }
                }
            }
            endObject()
            VideoDetails(
                    entries[0],
                    entries[1],
                    entries[2],
                    entries[3],
                    entries[4],
                    entries[5],
                    entries[6],
                    entries[7],
                    entries[8],
                    entries[9],
                    entries[10],
                    entries[11],
                    entries[12],
                    entries[13],
                    entries[14],
                    entries[15],
                    entries[16],
                    entries[17],
                    entries[18],
                    entries[19],
                    entries[20],
                    entries[21],
                    entries[22],
                    entries[23],
                    thumbnail
            )
        }
    }

    companion object {
        const val FILENAME = "filename"
        const val TITLE = "title"
        const val VCODEC = "vcodec"
        const val ACODEC = "acodec"
        const val DURATION = "duration"
        const val FILESIZE = "filesize"
        const val WIDTH = "width"
        const val HEIGHT = "height"
        const val BITRATE = "bitrate"
        const val FRAMERATE = "framerate"
        const val ENCODER = "encoder"
        const val ENCODED_BY = "encodedBy"
        const val DATE = "date"
        const val CREATION_TIME = "creationTime"
        const val ARTIST = "artist"
        const val ALBUM = "album"
        const val ALBUM_ARTIST = "albumArtist"
        const val TRACK = "track"
        const val GENRE = "genre"
        const val COMPOSER = "composer"
        const val PERFORMER = "performer"
        const val COPYRIGHT = "copyright"
        const val PUBLISHER = "publisher"
        const val LANGUAGE = "language"
        const val THUMBNAIL = "thumbnail"
    }
}

Bitmap 被简单地转换为 IntArray,然后包含位图中每个像素的 Int 值以及位图的宽度和高度作为该数组的最后两个条目。这个 IntArray 然后被转换为 Json。将其转换回 Bitmap 只需将此过程反转即可。

以下代码将自定义 TypeAdapter 注册到 Gson

    private val gson = GsonBuilder()
            .registerTypeAdapter(VideoDetails::class.java, VideoDetailsTypeAdapter())
            .create()