如何使用 AnimatedImageDrawable 显示以 ByteBuffer 作为源的动画 GIF
How to use AnimatedImageDrawable for showing animated GIFs with a ByteBuffer as source
我正在试验 Android 9 中引入的新 AnimatedImageDrawable。我正在尝试显示动画 GIF,从 ByteBuffer 创建源。
使用文件作为源渲染 GIF 效果很好。
此代码无效
ImageDecoder.createSource(ByteBuffer.wrap(file.readBytes())).also { source ->
ImageDecoder.decodeDrawable(source).also {
imageView.setImageDrawable(it)
(it as? AnimatedImageDrawable)?.start()
}
}
然而这有效:
ImageDecoder.createSource(file).also { source ->
ImageDecoder.decodeDrawable(source).also {
imageView.setImageDrawable(it)
(it as? AnimatedImageDrawable)?.start()
}
}
我怀疑可能存在一些线程问题,但我一直无法弄清楚如何解决它。我尝试在 Main 范围内的协程中调用 AnimatedImageDrawable 的启动函数,但我得到了同样的错误。
我希望这两种方法的工作原理相同,但是我遇到了本机崩溃并显示以下消息:
A/libc: Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 4499 (AnimatedImageTh), pid 4453
2019-07-11 15:18:00.156 4504-4504/? A/DEBUG: Abort message: 'Failed to get JNIEnv for JavaVM: 0x756e71a400'
2019-07-11 15:18:00.212 4504-4504/? A/DEBUG: backtrace:
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #00 pc 0000000000021c9c /system/lib64/libc.so (abort+112)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #01 pc 00000000000080dc /system/lib64/liblog.so (__android_log_assert+312)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #02 pc 00000000001552b0 /system/lib64/libandroid_runtime.so (android::get_env_or_die(_JavaVM*)+116)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #03 pc 000000000013fe58 /system/lib64/libandroid_runtime.so (ByteArrayStream::read(void*, unsigned long)+48)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #04 pc 000000000017b498 /system/lib64/libhwui.so (SkStreamBuffer::getDataAtPosition(unsigned long, unsigned long)+244)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #05 pc 000000000043a8d0 /system/lib64/libhwui.so (SkGIFColorMap::buildTable(SkStreamBuffer*, SkColorType, int) const+180)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #06 pc 000000000016ca9c /system/lib64/libhwui.so (SkGifCodec::initializeColorTable(SkImageInfo const&, int)+68)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #07 pc 000000000016ce30 /system/lib64/libhwui.so (SkGifCodec::prepareToDecode(SkImageInfo const&, SkCodec::Options const&)+436)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #08 pc 000000000016d070 /system/lib64/libhwui.so (SkGifCodec::onGetPixels(SkImageInfo const&, void*, unsigned long, SkCodec::Options const&, int*)+48)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #09 pc 000000000016aebc /system/lib64/libhwui.so (SkCodec::getPixels(SkImageInfo const&, void*, unsigned long, SkCodec::Options const*)+592)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #10 pc 0000000000162b30 /system/lib64/libhwui.so (SkAnimatedImage::decodeNextFrame()+1068)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #11 pc 00000000000ec234 /system/lib64/libhwui.so (android::AnimatedImageDrawable::decodeNextFrame()+40)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #12 pc 00000000000ee9a0 /system/lib64/libhwui.so (std::__1::packaged_task<android::AnimatedImageDrawable::Snapshot ()>::operator()()+88)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #13 pc 000000000043f664 /system/lib64/libhwui.so (android::uirenderer::WorkQueue::process()+168)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #14 pc 000000000047feb4 /system/lib64/libhwui.so (android::uirenderer::ThreadBase::threadLoop()+176)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #15 pc 000000000000f9f4 /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+264)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #16 pc 00000000000847b8 /system/lib64/libc.so (__pthread_start(void*)+36)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #17 pc 0000000000023574 /system/lib64/libc.so (__start_thread+68)
我意识到当它已经直接处理文件时尝试实现这一点可能没有意义,但我很好奇为什么在使用 ByteBuffer 时失败。
我有 gif 动画,所以我在 assets 文件夹中添加了 gif,然后调用下面的方法,该方法使用协程显示图像
private fun updateImageWithImageDecoder(assetFileName: String) {
val context = requireContext()
GlobalScope.launch(Dispatchers.Default) {
val source = ImageDecoder.createSource(context.assets, assetFileName)
val drawable = ImageDecoder.decodeDrawable(source)
GlobalScope.launch(Dispatchers.Main) {
imageView.setImageDrawable(drawable)
if (drawable is AnimatedImageDrawable) {
drawable.start()
}
}
}
}
此崩溃是由 Android framework issue 引起的。您可以通过不使用 ByteBuffer
来解决此问题。例如,将 ByteBuffer
写入 File
然后使用 ImageDecoder.createSource(file)
将解决此问题。
我正在试验 Android 9 中引入的新 AnimatedImageDrawable。我正在尝试显示动画 GIF,从 ByteBuffer 创建源。
使用文件作为源渲染 GIF 效果很好。
此代码无效
ImageDecoder.createSource(ByteBuffer.wrap(file.readBytes())).also { source ->
ImageDecoder.decodeDrawable(source).also {
imageView.setImageDrawable(it)
(it as? AnimatedImageDrawable)?.start()
}
}
然而这有效:
ImageDecoder.createSource(file).also { source ->
ImageDecoder.decodeDrawable(source).also {
imageView.setImageDrawable(it)
(it as? AnimatedImageDrawable)?.start()
}
}
我怀疑可能存在一些线程问题,但我一直无法弄清楚如何解决它。我尝试在 Main 范围内的协程中调用 AnimatedImageDrawable 的启动函数,但我得到了同样的错误。
我希望这两种方法的工作原理相同,但是我遇到了本机崩溃并显示以下消息:
A/libc: Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 4499 (AnimatedImageTh), pid 4453
2019-07-11 15:18:00.156 4504-4504/? A/DEBUG: Abort message: 'Failed to get JNIEnv for JavaVM: 0x756e71a400'
2019-07-11 15:18:00.212 4504-4504/? A/DEBUG: backtrace:
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #00 pc 0000000000021c9c /system/lib64/libc.so (abort+112)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #01 pc 00000000000080dc /system/lib64/liblog.so (__android_log_assert+312)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #02 pc 00000000001552b0 /system/lib64/libandroid_runtime.so (android::get_env_or_die(_JavaVM*)+116)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #03 pc 000000000013fe58 /system/lib64/libandroid_runtime.so (ByteArrayStream::read(void*, unsigned long)+48)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #04 pc 000000000017b498 /system/lib64/libhwui.so (SkStreamBuffer::getDataAtPosition(unsigned long, unsigned long)+244)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #05 pc 000000000043a8d0 /system/lib64/libhwui.so (SkGIFColorMap::buildTable(SkStreamBuffer*, SkColorType, int) const+180)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #06 pc 000000000016ca9c /system/lib64/libhwui.so (SkGifCodec::initializeColorTable(SkImageInfo const&, int)+68)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #07 pc 000000000016ce30 /system/lib64/libhwui.so (SkGifCodec::prepareToDecode(SkImageInfo const&, SkCodec::Options const&)+436)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #08 pc 000000000016d070 /system/lib64/libhwui.so (SkGifCodec::onGetPixels(SkImageInfo const&, void*, unsigned long, SkCodec::Options const&, int*)+48)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #09 pc 000000000016aebc /system/lib64/libhwui.so (SkCodec::getPixels(SkImageInfo const&, void*, unsigned long, SkCodec::Options const*)+592)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #10 pc 0000000000162b30 /system/lib64/libhwui.so (SkAnimatedImage::decodeNextFrame()+1068)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #11 pc 00000000000ec234 /system/lib64/libhwui.so (android::AnimatedImageDrawable::decodeNextFrame()+40)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #12 pc 00000000000ee9a0 /system/lib64/libhwui.so (std::__1::packaged_task<android::AnimatedImageDrawable::Snapshot ()>::operator()()+88)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #13 pc 000000000043f664 /system/lib64/libhwui.so (android::uirenderer::WorkQueue::process()+168)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #14 pc 000000000047feb4 /system/lib64/libhwui.so (android::uirenderer::ThreadBase::threadLoop()+176)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #15 pc 000000000000f9f4 /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+264)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #16 pc 00000000000847b8 /system/lib64/libc.so (__pthread_start(void*)+36)
2019-07-11 15:18:00.213 4504-4504/? A/DEBUG: #17 pc 0000000000023574 /system/lib64/libc.so (__start_thread+68)
我意识到当它已经直接处理文件时尝试实现这一点可能没有意义,但我很好奇为什么在使用 ByteBuffer 时失败。
我有 gif 动画,所以我在 assets 文件夹中添加了 gif,然后调用下面的方法,该方法使用协程显示图像
private fun updateImageWithImageDecoder(assetFileName: String) {
val context = requireContext()
GlobalScope.launch(Dispatchers.Default) {
val source = ImageDecoder.createSource(context.assets, assetFileName)
val drawable = ImageDecoder.decodeDrawable(source)
GlobalScope.launch(Dispatchers.Main) {
imageView.setImageDrawable(drawable)
if (drawable is AnimatedImageDrawable) {
drawable.start()
}
}
}
}
此崩溃是由 Android framework issue 引起的。您可以通过不使用 ByteBuffer
来解决此问题。例如,将 ByteBuffer
写入 File
然后使用 ImageDecoder.createSource(file)
将解决此问题。