Work on result
This commit is contained in:
parent
4ef644632a
commit
31c7529d45
|
@ -53,7 +53,7 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val inputStream: InputStream? = input
|
private var inputStream: InputStream? = input
|
||||||
private var result: Result<Drawable>? = null
|
private var result: Result<Drawable>? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +65,9 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
*/
|
*/
|
||||||
suspend fun decodeApng(
|
suspend fun decodeApng(
|
||||||
context: Context
|
context: Context
|
||||||
): Drawable = withContext(Dispatchers.Default) {
|
): Result<Drawable> =
|
||||||
|
kotlin.runCatching {
|
||||||
|
withContext(Dispatchers.Default) {
|
||||||
val inputStream = BufferedInputStream(inputStream)
|
val inputStream = BufferedInputStream(inputStream)
|
||||||
val bytes = ByteArray(8)
|
val bytes = ByteArray(8)
|
||||||
inputStream.mark(8)
|
inputStream.mark(8)
|
||||||
|
@ -83,7 +85,8 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
var tnrs: ByteArray? = null
|
var tnrs: ByteArray? = null
|
||||||
var maxWidth = 0
|
var maxWidth = 0
|
||||||
var maxHeight = 0
|
var maxHeight = 0
|
||||||
var blendOp: Utils.Companion.BlendOp = Utils.Companion.BlendOp.APNG_BLEND_OP_SOURCE
|
var blendOp: Utils.Companion.BlendOp =
|
||||||
|
Utils.Companion.BlendOp.APNG_BLEND_OP_SOURCE
|
||||||
var disposeOp: Utils.Companion.DisposeOp =
|
var disposeOp: Utils.Companion.DisposeOp =
|
||||||
Utils.Companion.DisposeOp.APNG_DISPOSE_OP_NONE
|
Utils.Companion.DisposeOp.APNG_DISPOSE_OP_NONE
|
||||||
|
|
||||||
|
@ -494,13 +497,13 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
inputStream.close()
|
inputStream.close()
|
||||||
}
|
}
|
||||||
return@withContext drawable
|
drawable
|
||||||
} else {
|
} else {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
Log.i(TAG, "Decoding non APNG stream")
|
Log.i(TAG, "Decoding non APNG stream")
|
||||||
inputStream.reset()
|
inputStream.reset()
|
||||||
|
|
||||||
return@withContext if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
val bytesRead: ByteArray
|
val bytesRead: ByteArray
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
bytesRead = inputStream.readBytes()
|
bytesRead = inputStream.readBytes()
|
||||||
|
@ -519,16 +522,17 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
inputStream.close()
|
inputStream.close()
|
||||||
}
|
}
|
||||||
drawable
|
drawable!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getDecoded(context: Context): Result<Drawable> {
|
suspend fun getDecoded(context: Context): Result<Drawable> {
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = kotlin.runCatching {
|
result =
|
||||||
decodeApng(context)
|
decodeApng(context)
|
||||||
}
|
|
||||||
|
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
|
@ -537,6 +541,8 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
return Result.failure(it)
|
return Result.failure(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inputStream = null
|
||||||
}
|
}
|
||||||
|
|
||||||
return result ?: Result.failure(NullPointerException("result is null"))
|
return result ?: Result.failure(NullPointerException("result is null"))
|
||||||
|
@ -639,12 +645,13 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
* @param config Decoder configuration
|
* @param config Decoder configuration
|
||||||
* @return [ApngDrawable] if successful and an [AnimatedImageDrawable] if the image decoded is not an APNG but a gif.
|
* @return [ApngDrawable] if successful and an [AnimatedImageDrawable] if the image decoded is not an APNG but a gif.
|
||||||
*/
|
*/
|
||||||
@Suppress("unused", "BlockingMethodInNonBlockingContext")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
suspend fun constructFromUrl(
|
suspend fun constructFromUrl(
|
||||||
url: URL,
|
url: URL,
|
||||||
config: Config = Config()
|
config: Config = Config()
|
||||||
) =
|
): Result<ApngDecoder> =
|
||||||
|
kotlin.runCatching {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
ApngDecoder(
|
ApngDecoder(
|
||||||
ByteArrayInputStream(Loader.load(url)),
|
ByteArrayInputStream(Loader.load(url)),
|
||||||
|
@ -652,4 +659,5 @@ class ApngDecoder(input: InputStream, val config: Config) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -153,7 +153,9 @@ class ApngLoader(parent: Job? = null) {
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
): Result<Drawable> {
|
): Result<Drawable> {
|
||||||
val result = ApngDecoder.constructFromUrl(url, config).getDecoded(context)
|
val result =
|
||||||
|
ApngDecoder.constructFromUrl(url, config).getOrElse { return Result.failure(it) }
|
||||||
|
.getDecoded(context)
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val drawable = result.getOrNull()
|
val drawable = result.getOrNull()
|
||||||
|
@ -204,10 +206,10 @@ class ApngLoader(parent: Job? = null) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
context.assets.open(string.replace("file:///android_asset/", ""))
|
context.assets.open(string.replace("file:///android_asset/", ""))
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.getOrElse {
|
||||||
return Result.failure(it)
|
return Result.failure(it)
|
||||||
}
|
}
|
||||||
val result = ApngDecoder(inputStream.getOrThrow(), config).getDecoded(context)
|
val result = ApngDecoder(inputStream, config).getDecoded(context)
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val drawable = result.getOrNull()
|
val drawable = result.getOrNull()
|
||||||
|
@ -246,11 +248,9 @@ class ApngLoader(parent: Job? = null) {
|
||||||
coroutineScope.launch(Dispatchers.Default) {
|
coroutineScope.launch(Dispatchers.Default) {
|
||||||
val drawable = decodeApngInto(context, file, imageView, config)
|
val drawable = decodeApngInto(context, file, imageView, config)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (drawable.isSuccess) {
|
drawable
|
||||||
callback?.onSuccess(drawable.getOrNull()!!)
|
.onSuccess { callback?.onSuccess(it) }
|
||||||
} else {
|
.onFailure { callback?.onError(it) }
|
||||||
callback?.onError(drawable.exceptionOrNull()!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,11 +274,9 @@ class ApngLoader(parent: Job? = null) {
|
||||||
) = coroutineScope.launch(Dispatchers.Default) {
|
) = coroutineScope.launch(Dispatchers.Default) {
|
||||||
val drawable = decodeApngInto(context, uri, imageView, config)
|
val drawable = decodeApngInto(context, uri, imageView, config)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (drawable.isSuccess) {
|
drawable
|
||||||
callback?.onSuccess(drawable.getOrNull()!!)
|
.onSuccess { callback?.onSuccess(it) }
|
||||||
} else {
|
.onFailure { callback?.onError(it) }
|
||||||
callback?.onError(drawable.exceptionOrNull()!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,11 +298,9 @@ class ApngLoader(parent: Job? = null) {
|
||||||
) = coroutineScope.launch(Dispatchers.Default) {
|
) = coroutineScope.launch(Dispatchers.Default) {
|
||||||
val drawable = decodeApngInto(context, res, imageView, config)
|
val drawable = decodeApngInto(context, res, imageView, config)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (drawable.isSuccess) {
|
drawable
|
||||||
callback?.onSuccess(drawable.getOrNull()!!)
|
.onSuccess { callback?.onSuccess(it) }
|
||||||
} else {
|
.onFailure { callback?.onError(it) }
|
||||||
callback?.onError(drawable.exceptionOrNull()!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,14 +323,13 @@ class ApngLoader(parent: Job? = null) {
|
||||||
) = coroutineScope.launch(Dispatchers.Default) {
|
) = coroutineScope.launch(Dispatchers.Default) {
|
||||||
val drawable = decodeApngInto(context, url, imageView, config)
|
val drawable = decodeApngInto(context, url, imageView, config)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (drawable.isSuccess) {
|
drawable
|
||||||
callback?.onSuccess(drawable.getOrNull()!!)
|
.onSuccess { callback?.onSuccess(it) }
|
||||||
} else {
|
.onFailure { callback?.onError(it) }
|
||||||
callback?.onError(drawable.exceptionOrNull()!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load Apng into an imageView, asynchronously.
|
* Load Apng into an imageView, asynchronously.
|
||||||
* @param context Context needed for decoding the image and creating the animation drawable.
|
* @param context Context needed for decoding the image and creating the animation drawable.
|
||||||
|
|
Loading…
Reference in New Issue