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

Commit

Permalink
Merge pull request #327 from xxjy/master
Browse files Browse the repository at this point in the history
Memory thrashing problem.
  • Loading branch information
painld6 authored Nov 28, 2020
2 parents eae4719 + 7877a37 commit f25b11a
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import android.graphics.Canvas
import android.widget.ImageView
import com.opensource.svgaplayer.SVGAVideoEntity
import com.opensource.svgaplayer.entities.SVGAVideoSpriteFrameEntity
import com.opensource.svgaplayer.utils.Pools
import com.opensource.svgaplayer.utils.SVGAScaleInfo
import kotlin.math.max

/**
* Created by cuiminghui on 2017/3/29.
Expand All @@ -14,7 +16,13 @@ open internal class SGVADrawer(val videoItem: SVGAVideoEntity) {

val scaleInfo = SVGAScaleInfo()

inner class SVGADrawerSprite(val matteKey: String?, val imageKey: String?, val frameEntity: SVGAVideoSpriteFrameEntity)
private val spritePool = Pools.SimplePool<SVGADrawerSprite>(max(1, videoItem.spriteList.size))

inner class SVGADrawerSprite(var _matteKey: String? = null, var _imageKey: String? = null, var _frameEntity: SVGAVideoSpriteFrameEntity? = null) {
val matteKey get() = _matteKey
val imageKey get() = _imageKey
val frameEntity get() = _frameEntity!!
}

internal fun requestFrameSprites(frameIndex: Int): List<SVGADrawerSprite> {
return videoItem.spriteList.mapNotNull {
Expand All @@ -23,13 +31,21 @@ open internal class SGVADrawer(val videoItem: SVGAVideoEntity) {
if (!imageKey.endsWith(".matte") && it.frames[frameIndex].alpha <= 0.0) {
return@mapNotNull null
}
return@mapNotNull SVGADrawerSprite(it.matteKey, it.imageKey, it.frames[frameIndex])
return@mapNotNull (spritePool.acquire() ?: SVGADrawerSprite()).apply {
_matteKey = it.matteKey
_imageKey = it.imageKey
_frameEntity = it.frames[frameIndex]
}
}
}
return@mapNotNull null
}
}

internal fun releaseFrameSprites(sprites: List<SVGADrawerSprite>) {
sprites.forEach { spritePool.release(it) }
}

open fun drawFrame(canvas : Canvas, frameIndex: Int, scaleType: ImageView.ScaleType) {
scaleInfo.performScaleType(canvas.width.toFloat(),canvas.height.toFloat(), videoItem.videoSize.width.toFloat(), videoItem.videoSize.height.toFloat(), scaleType)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ internal class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVG
}
}
}
releaseFrameSprites(sprites)
}

private fun isMatteBegin(spriteIndex: Int, sprites: List<SVGADrawerSprite>): Boolean {
Expand All @@ -101,7 +102,7 @@ internal class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVG
svgaDrawerSprite.matteKey?.let {
if (it.length > 0) {
sprites.get(index - 1)?.let { lastSprite ->
if (lastSprite.matteKey == null || lastSprite.matteKey.length == 0) {
if (lastSprite.matteKey.isNullOrEmpty()) {
boolArray[index] = true
} else {
if (lastSprite.matteKey != svgaDrawerSprite.matteKey) {
Expand Down Expand Up @@ -135,7 +136,7 @@ internal class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVG
boolArray[index] = true
} else {
sprites.get(index + 1)?.let { nextSprite ->
if (nextSprite.matteKey == null || nextSprite.matteKey.length == 0) {
if (nextSprite.matteKey.isNullOrEmpty()) {
boolArray[index] = true
} else {
if (nextSprite.matteKey != svgaDrawerSprite.matteKey) {
Expand Down Expand Up @@ -188,7 +189,7 @@ internal class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVG
val imageKey = sprite.imageKey ?: return
val isHidden = dynamicItem.dynamicHidden[imageKey] == true
if (isHidden) { return }
val bitmapKey = imageKey.replace(".matte", "")
val bitmapKey = if (imageKey.endsWith(".matte")) imageKey.substring(0, imageKey.length - 6) else imageKey
val drawingBitmap = (dynamicItem.dynamicImage[bitmapKey] ?: videoItem.imageMap[bitmapKey]) ?: return
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
val paint = this.sharedValues.sharedPaint()
Expand Down
102 changes: 102 additions & 0 deletions library/src/main/java/com/opensource/svgaplayer/utils/Pools.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.opensource.svgaplayer.utils

/**
* Helper class for creating pools of objects. An example use looks like this:
* <pre>
* public class MyPooledClass {
*
* private static final SynchronizedPool<MyPooledClass> sPool =
* new SynchronizedPool<MyPooledClass>(10);
*
* public static MyPooledClass obtain() {
* MyPooledClass instance = sPool.acquire();
* return (instance != null) ? instance : new MyPooledClass();
* }
*
* public void recycle() {
* // Clear state if needed.
* sPool.release(this);
* }
*
* . . .
* }
* </pre>
*
*/
class Pools private constructor() {

/**
* Interface for managing a pool of objects.
*
* @param <T> The pooled type.
*/
interface Pool<T> {
/**
* @return An instance from the pool if such, null otherwise.
*/
fun acquire(): T?

/**
* Release an instance to the pool.
*
* @param instance The instance to release.
* @return Whether the instance was put in the pool.
*
* @throws IllegalStateException If the instance is already in the pool.
*/
fun release(instance: T): Boolean
}

/**
* Simple (non-synchronized) pool of objects.
*
* @param maxPoolSize The max pool size.
*
* @throws IllegalArgumentException If the max pool size is less than zero.
*
* @param <T> The pooled type.
*/
open class SimplePool<T>(maxPoolSize: Int) : Pool<T> {
private val mPool: Array<Any?>
private var mPoolSize = 0

init {
require(maxPoolSize > 0) { "The max pool size must be > 0" }
mPool = arrayOfNulls(maxPoolSize)
}

@Suppress("UNCHECKED_CAST")
override fun acquire(): T? {
if (mPoolSize > 0) {
val lastPooledIndex = mPoolSize - 1
val instance = mPool[lastPooledIndex] as T?
mPool[lastPooledIndex] = null
mPoolSize--
return instance
}
return null
}

override fun release(instance: T): Boolean {
check(!isInPool(instance)) { "Already in the pool!" }
if (mPoolSize < mPool.size) {
mPool[mPoolSize] = instance
mPoolSize++
return true
}
return false
}

private fun isInPool(instance: T): Boolean {
for (i in 0 until mPoolSize) {
if (mPool[i] === instance) {
return true
}
}
return false
}

}


}

0 comments on commit f25b11a

Please sign in to comment.