我的应用程序崩溃,除了出现此错误外,没有任何堆栈跟踪:
A/libc: Fatal signal 11 (SIGSEGV), code 128, fault addr 0x0 in tid 12680 (dio.downloadapp)
经过一些故障排除后,我将其范围缩小到导致此错误的那一行:
val details = gson.fromJson(fileReader, VideoDetails::class.java)
它来自 View 模型的方法:
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类的方法创建的:
private fun VideoDetails.saveVideoDetails() {
val json = gson.toJson(this)
File(applicationContext.filesDir, VIDEO_DETAILS_FILE).writeText(json)
}
另外,
VideoDetails
只是一个带有一串字符串和一个位图的数据类: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
数据类中的位图。显然,Gson无法处理位图。我决定不删除位图,而是为TypeAdapter
创建一个自定义 VideoDetails
。这样,我不必更改VideoDetails
类,因此不必更改代码的许多部分。
完整代码:
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"
}
}
将位图简单地转换为
IntArray
,然后它包含位图中每个像素的Int值以及位图的宽度和高度,作为该数组的最后两个条目。然后将此IntArray
转换为Json
。将其转换回Bitmap只需逆转此过程即可。以下代码将自定义
TypeAdapter
注册到Gson
。 private val gson = GsonBuilder()
.registerTypeAdapter(VideoDetails::class.java, VideoDetailsTypeAdapter())
.create()