Skip to content
This repository was archived by the owner on Feb 6, 2023. It is now read-only.

Commit b843ee3

Browse files
author
xtim.cc
committed
1 SVGAParser.kt 添加缓存SVGA文件到本地的扩展[SVGACache.kt]
2 SVGADrawable.kt SVGAImageView.kt SVGAVideoEntity.kt 公开clear()方法. 3 SVGAImageView.kt 添加clearsAfterDetached,用于控制imageview在onDetach的时候是否要自动调用clear(). 暂时为需要给RecyclerView缓存drawable或者entity的人士提供临时解决方案.用完记得调用clear()!!!!!!! 4 SVGAVideoEntity.kt generateAudioFileMap 方法每次打开同一个文件会解压一次mp3.缓存文件夹会越来越大.改为固定名字. 5 SVGAVideoEntity.kt 里面soundPool如果解析时load同一个svga的声音文件会出现无回调的情况,导致这里的callback不执行, 原因暂时未知.目前解决方案是公开imageview,drawable,entity的clear(),然后在播放带声音的svgaimageview处, 把解析完的drawable或者entity缓存下来,下次直接播放.用完再调用clear()!!!!!!!没有声音的不存在此问题. (真实场景如下:持续以队列形式播放同一个带声音的svga,由于2.5.8自动clear(),且clear()相关方法没有公开, 只能一直重新decodeFromURL同一个远程svga文件,会导致onComplete与onError不回调)
1 parent 84fcf55 commit b843ee3

File tree

3 files changed

+98
-62
lines changed

3 files changed

+98
-62
lines changed

library/src/main/java/com/opensource/svgaplayer/SVGACache.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,21 @@ object SVGACache {
2727
this.type = type
2828
}
2929

30+
// fun clearCache(context: Context?){
31+
// context ?: return
32+
// cacheDir = "${context.cacheDir.absolutePath}/svga/"
33+
// File(cacheDir).takeIf { it.exists() }?.delete()
34+
// }
35+
3036
fun isInitialized(): Boolean {
3137
return "/" != cacheDir
3238
}
3339

3440
fun isDefaultCache(): Boolean = type == Type.DEFAULT
3541

3642
fun isCached(cacheKey: String): Boolean {
37-
return (if (isDefaultCache()) buildCacheDir(cacheKey) else buildCacheFile(
38-
cacheKey
43+
return (if (isDefaultCache()) buildCacheDir(cacheKey) else buildSvgaFile(
44+
cacheKey
3945
)).exists()
4046
}
4147

@@ -56,8 +62,12 @@ object SVGACache {
5662
return File("$cacheDir$cacheKey/")
5763
}
5864

59-
fun buildCacheFile(cacheKey: String): File {
65+
fun buildSvgaFile(cacheKey: String): File {
6066
return File("$cacheDir$cacheKey.svga")
6167
}
6268

69+
fun buildAudioFile(audio: String): File {
70+
return File("$cacheDir$audio.mp3")
71+
}
72+
6373
}

library/src/main/java/com/opensource/svgaplayer/SVGAParser.kt

Lines changed: 78 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import org.json.JSONObject
1010
import java.io.*
1111
import java.net.HttpURLConnection
1212
import java.net.URL
13-
import java.security.MessageDigest
1413
import java.util.concurrent.Executors
1514
import java.util.concurrent.ThreadPoolExecutor
1615
import java.util.concurrent.atomic.AtomicInteger
@@ -108,7 +107,7 @@ class SVGAParser(context: Context?) {
108107
private var mShareParser = SVGAParser(null)
109108

110109
internal var threadPoolExecutor = Executors.newCachedThreadPool { r ->
111-
Thread(r, "SVGAParser-Thread-${threadNum.getAndIncrement()}")
110+
Thread(r, "SVGAParser-Thread-${threadNum.getAndIncrement()}")
112111
}
113112

114113
fun setThreadPoolExecutor(executor: ThreadPoolExecutor) {
@@ -178,63 +177,90 @@ class SVGAParser(context: Context?) {
178177
}
179178
}
180179

180+
/**
181+
* 读取解析本地缓存的svga文件.
182+
*/
181183
fun _decodeFromCacheKey(cacheKey: String, callback: ParseCompletion?) {
182-
val svga = SVGACache.buildCacheFile(cacheKey)
184+
val svga = SVGACache.buildSvgaFile(cacheKey)
183185
try {
184-
LogUtils.info(TAG, "binary change to entity")
185-
FileInputStream(svga).use {
186-
LogUtils.info(TAG, "binary change to entity success")
187-
this.invokeCompleteCallback(
188-
SVGAVideoEntity(
189-
MovieEntity.ADAPTER.decode(it),
190-
SVGACache.buildCacheDir(cacheKey),
191-
mFrameWidth,
192-
mFrameHeight
193-
), callback
194-
)
186+
LogUtils.info(TAG, "cache.binary change to entity")
187+
FileInputStream(svga).use { inputStream ->
188+
try {
189+
readAsBytes(inputStream)?.let { bytes ->
190+
LogUtils.info(TAG, "cache.inflate start")
191+
inflate(bytes)?.let { inflateBytes ->
192+
LogUtils.info(TAG, "cache.inflate success")
193+
val videoItem = SVGAVideoEntity(
194+
MovieEntity.ADAPTER.decode(inflateBytes),
195+
File(cacheKey),
196+
mFrameWidth,
197+
mFrameHeight
198+
)
199+
videoItem.prepare {
200+
LogUtils.info(TAG, "cache.prepare success")
201+
this.invokeCompleteCallback(videoItem, callback)
202+
}
203+
} ?: doError("cache.inflate(bytes) cause exception", callback)
204+
} ?: doError("cache.readAsBytes(inputStream) cause exception", callback)
205+
} catch (e: Exception) {
206+
this.invokeErrorCallback(e, callback)
207+
} finally {
208+
inputStream.close()
209+
}
195210
}
196211
} catch (e: Exception) {
197-
LogUtils.error(TAG, "binary change to entity fail", e)
198-
SVGACache.buildCacheDir(cacheKey).delete()
199-
svga.delete()
212+
LogUtils.error(TAG, "cache.binary change to entity fail", e)
213+
svga.takeIf { it.exists() }?.delete()
200214
this.invokeErrorCallback(e, callback)
201215
}
202216
}
203217

218+
fun doError(error: String, callback: ParseCompletion?) {
219+
LogUtils.info(TAG, error)
220+
this.invokeErrorCallback(
221+
Exception(error),
222+
callback
223+
)
224+
}
225+
226+
/**
227+
* 读取解析来自URL的svga文件.并缓存成本地文件
228+
*/
204229
fun _decodeFromInputStream(
205-
inputStream: InputStream,
206-
cacheKey: String,
207-
callback: ParseCompletion?
230+
inputStream: InputStream,
231+
cacheKey: String,
232+
callback: ParseCompletion?
208233
) {
209234
threadPoolExecutor.execute {
210235
try {
236+
LogUtils.info(TAG, "Input.binary change to entity")
211237
readAsBytes(inputStream)?.let { bytes ->
212-
LogUtils.info(TAG, "decode from input stream, inflate start")
213-
inflate(bytes)?.let { inflateBytes ->
214-
threadPoolExecutor.execute {
215-
SVGACache.buildCacheFile(cacheKey).let { cacheFile ->
216-
cacheFile.takeIf { !it.exists() }?.createNewFile()
217-
FileOutputStream(cacheFile).write(inflateBytes)
218-
}
238+
threadPoolExecutor.execute {
239+
SVGACache.buildSvgaFile(cacheKey).let { cacheFile ->
240+
cacheFile.takeIf { !it.exists() }?.createNewFile()
241+
FileOutputStream(cacheFile).write(bytes)
219242
}
243+
}
244+
LogUtils.info(TAG, "Input.inflate start")
245+
inflate(bytes)?.let { inflateBytes ->
246+
LogUtils.info(TAG, "Input.inflate success")
220247
val videoItem = SVGAVideoEntity(
221-
MovieEntity.ADAPTER.decode(inflateBytes),
222-
File(cacheKey),
223-
mFrameWidth,
224-
mFrameHeight
248+
MovieEntity.ADAPTER.decode(inflateBytes),
249+
File(cacheKey),
250+
mFrameWidth,
251+
mFrameHeight
225252
)
253+
// 里面soundPool如果解析时load同一个svga的声音文件会出现无回调的情况,导致这里的callback不执行,
254+
// 原因暂时未知.目前解决方案是公开imageview,drawable,entity的clear(),然后在播放带声音
255+
// 的svgaimageview处,把解析完的drawable或者entity缓存下来,下次直接播放.用完再调用clear()
256+
// 在ImageView添加clearsAfterDetached,用于控制imageview在onDetach的时候是否要自动调用clear.
257+
// 以暂时缓解需要为RecyclerView缓存drawable或者entity的人士.用完记得调用clear()
226258
videoItem.prepare {
227-
LogUtils.info(TAG, "decode from input stream, inflate end")
259+
LogUtils.info(TAG, "Input.prepare success")
228260
this.invokeCompleteCallback(videoItem, callback)
229261
}
230-
} ?: this.invokeErrorCallback(
231-
Exception("inflate(bytes) cause exception"),
232-
callback
233-
)
234-
} ?: this.invokeErrorCallback(
235-
Exception("readAsBytes(inputStream) cause exception"),
236-
callback
237-
)
262+
} ?: doError("Input.inflate(bytes) cause exception", callback)
263+
} ?: doError("Input.readAsBytes(inputStream) cause exception", callback)
238264
} catch (e: Exception) {
239265
this.invokeErrorCallback(e, callback)
240266
} finally {
@@ -244,10 +270,10 @@ class SVGAParser(context: Context?) {
244270
}
245271

246272
fun decodeFromInputStream(
247-
inputStream: InputStream,
248-
cacheKey: String,
249-
callback: ParseCompletion?,
250-
closeInputStream: Boolean = false
273+
inputStream: InputStream,
274+
cacheKey: String,
275+
callback: ParseCompletion?,
276+
closeInputStream: Boolean = false
251277
) {
252278
if (mContext == null) {
253279
LogUtils.error(TAG, "在配置 SVGAParser context 前, 无法解析 SVGA 文件。")
@@ -277,24 +303,24 @@ class SVGAParser(context: Context?) {
277303
LogUtils.info(TAG, "decode from input stream, inflate start")
278304
inflate(bytes)?.let {
279305
val videoItem = SVGAVideoEntity(
280-
MovieEntity.ADAPTER.decode(it),
281-
File(cacheKey),
282-
mFrameWidth,
283-
mFrameHeight
306+
MovieEntity.ADAPTER.decode(it),
307+
File(cacheKey),
308+
mFrameWidth,
309+
mFrameHeight
284310
)
285311
videoItem.prepare {
286312
LogUtils.info(TAG, "decode from input stream, inflate end")
287313
this.invokeCompleteCallback(videoItem, callback)
288314
}
289315

290316
} ?: this.invokeErrorCallback(
291-
Exception("inflate(bytes) cause exception"),
292-
callback
317+
Exception("inflate(bytes) cause exception"),
318+
callback
293319
)
294320
}
295321
} ?: this.invokeErrorCallback(
296-
Exception("readAsBytes(inputStream) cause exception"),
297-
callback
322+
Exception("readAsBytes(inputStream) cause exception"),
323+
callback
298324
)
299325
} catch (e: java.lang.Exception) {
300326
this.invokeErrorCallback(e, callback)

library/src/main/java/com/opensource/svgaplayer/SVGAVideoEntity.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,12 @@ class SVGAVideoEntity {
200200
// 除数不能为 0
201201
return item
202202
}
203-
audiosFileMap[audio.audioKey]?.let {
204-
val fis = FileInputStream(it)
205-
val length = fis.available().toDouble()
206-
val offset = ((startTime / totalTime) * length).toLong()
207-
item.soundID = soundPool?.load(fis.fd, offset, length.toLong(), 1)
208-
fis.close()
203+
audiosFileMap[audio.audioKey]?.let { file ->
204+
FileInputStream(file).use {
205+
val length = it.available().toDouble()
206+
val offset = ((startTime / totalTime) * length).toLong()
207+
item.soundID = soundPool?.load(it.fd, offset, length.toLong(), 1)
208+
}
209209
}
210210
return item
211211
}
@@ -221,7 +221,7 @@ class SVGAVideoEntity {
221221
val audiosFileMap = HashMap<String, File>()
222222
if (audiosDataMap.count() > 0) {
223223
audiosDataMap.forEach {
224-
val audioCache = File(it.key + ".mp3")
224+
val audioCache = SVGACache.buildAudioFile(it.key)
225225
audiosFileMap[it.key] =
226226
audioCache.takeIf { file -> file.exists() } ?: generateAudioFile(
227227
audioCache,

0 commit comments

Comments
 (0)