Skip to content

Commit

Permalink
improve: Improve reset preferredTileSize
Browse files Browse the repository at this point in the history
  • Loading branch information
panpf committed Aug 16, 2024
1 parent 96cad5d commit 78241d6
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import com.github.panpf.zoomimage.subsampling.internal.TileDecoder
import com.github.panpf.zoomimage.subsampling.internal.TileManager
import com.github.panpf.zoomimage.subsampling.internal.TileManager.Companion.DefaultPausedContinuousTransformTypes
import com.github.panpf.zoomimage.subsampling.internal.calculatePreferredTileSize
import com.github.panpf.zoomimage.subsampling.internal.checkNewPreferredTileSize
import com.github.panpf.zoomimage.subsampling.internal.decodeAndCreateTileDecoder
import com.github.panpf.zoomimage.subsampling.internal.toIntroString
import com.github.panpf.zoomimage.util.IntSizeCompat
Expand All @@ -64,7 +65,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.abs
import kotlin.math.roundToInt


Expand Down Expand Up @@ -289,25 +289,21 @@ class SubsamplingState(
// Size animations cause frequent changes in containerSize, so a delayed reset avoids this problem
@Suppress("OPT_IN_USAGE")
snapshotFlow { zoomableState.containerSize }.debounce(80).collect {
val oldPreferredTileSize = this@SubsamplingState.preferredTileSize.toCompat()
val newPreferredTileSize = calculatePreferredTileSize(it.toCompat())
val finalPreferredTileSize = if (preferredTileSize.isEmpty()) {
newPreferredTileSize.toPlatform()
} else if (abs(newPreferredTileSize.width - preferredTileSize.width) >=
// When the width changes by more than 1x, the preferredTileSize is recalculated to reduce the need to reset the TileManager
preferredTileSize.width * (if (newPreferredTileSize.width > preferredTileSize.width) 1f else 0.5f)
) {
newPreferredTileSize.toPlatform()
} else if (abs(newPreferredTileSize.height - preferredTileSize.height) >=
preferredTileSize.height * (if (newPreferredTileSize.height > preferredTileSize.height) 1f else 0.5f)
) {
// When the height changes by more than 1x, the preferredTileSize is recalculated to reduce the need to reset the TileManager
newPreferredTileSize.toPlatform()
} else {
null
val checkPassed = checkNewPreferredTileSize(
oldPreferredTileSize = oldPreferredTileSize,
newPreferredTileSize = newPreferredTileSize
)
logger.d {
"SubsamplingState. reset preferredTileSize. " +
"oldPreferredTileSize=$oldPreferredTileSize, " +
"newPreferredTileSize=$newPreferredTileSize, " +
"checkPassed=$checkPassed. " +
"'${imageKey}'"
}
logger.d { "SubsamplingState. reset preferredTileSize. finalPreferredTileSize=$finalPreferredTileSize. '${imageKey}" }
if (finalPreferredTileSize != null) {
preferredTileSize = finalPreferredTileSize
if (checkPassed) {
this@SubsamplingState.preferredTileSize = newPreferredTileSize.toPlatform()
}
}
}
Expand Down Expand Up @@ -390,7 +386,6 @@ class SubsamplingState(
}

private fun resetTileDecoder(caller: String) {
// TODO Unexpectedly executed twice in a row
cleanTileManager("resetTileDecoder:$caller")
cleanTileDecoder("resetTileDecoder:$caller")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,39 @@ fun List<SamplingTiles>.toIntroString(): String {
*/
fun calculatePreferredTileSize(containerSize: IntSizeCompat): IntSizeCompat {
return containerSize / 2
}

/**
* Returns true if the new preferred tile size is doubled in width or height or reduced by half, which can significantly reduce the number of times the TileManager is reset when the container size changes frequently (window resizing)
*
* @see com.github.panpf.zoomimage.core.common.test.subsampling.internal.SubsamplingsCommonTest.testCheckNewPreferredTileSize
*/
fun checkNewPreferredTileSize(
oldPreferredTileSize: IntSizeCompat,
newPreferredTileSize: IntSizeCompat
): Boolean {
if (newPreferredTileSize.isEmpty()) {
return false
}
if (oldPreferredTileSize.isEmpty()) {
return true
}

val widthDifferent = abs(newPreferredTileSize.width - oldPreferredTileSize.width)
val widthTargetMultiple =
if (newPreferredTileSize.width > oldPreferredTileSize.width) 1f else 0.5f
val widthTarget = oldPreferredTileSize.width * widthTargetMultiple
if (widthDifferent >= widthTarget) {
return true
}

val heightDifferent = abs(newPreferredTileSize.height - oldPreferredTileSize.height)
val heightTargetMultiple =
if (newPreferredTileSize.height > oldPreferredTileSize.height) 1f else 0.5f
val heightTarget = oldPreferredTileSize.height * heightTargetMultiple
if (heightDifferent >= heightTarget) {
return true
}

return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.github.panpf.zoomimage.core.common.test.subsampling.internal
import com.github.panpf.zoomimage.subsampling.internal.calculatePreferredTileSize
import com.github.panpf.zoomimage.subsampling.internal.calculateTileGridMap
import com.github.panpf.zoomimage.subsampling.internal.canUseSubsamplingByAspectRatio
import com.github.panpf.zoomimage.subsampling.internal.checkNewPreferredTileSize
import com.github.panpf.zoomimage.subsampling.internal.toIntroString
import com.github.panpf.zoomimage.util.IntSizeCompat
import com.github.panpf.zoomimage.util.ScaleFactorCompat
Expand Down Expand Up @@ -116,4 +117,179 @@ class SubsamplingsCommonTest {
/* actual = */ calculatePreferredTileSize(IntSizeCompat(1000, 2000))
)
}

@Test
fun testCheckNewPreferredTileSize() {
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(200, 100)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(100, 200)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(200, 200)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(50, 100)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(100, 50)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(50, 50)
)
)

assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(0, 0)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(0, 0)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(0, 0)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(0, 0)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(0, 0)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(0, 0)
)
)

assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(199, 100)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(100, 199)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(199, 199)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(51, 100)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(100, 51)
)
)
assertEquals(
expected = false,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(100, 100),
newPreferredTileSize = IntSizeCompat(51, 51)
)
)

assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(0, 0),
newPreferredTileSize = IntSizeCompat(199, 100)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(0, 0),
newPreferredTileSize = IntSizeCompat(100, 199)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(0, 0),
newPreferredTileSize = IntSizeCompat(199, 199)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(0, 0),
newPreferredTileSize = IntSizeCompat(51, 100)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(0, 0),
newPreferredTileSize = IntSizeCompat(100, 51)
)
)
assertEquals(
expected = true,
checkNewPreferredTileSize(
oldPreferredTileSize = IntSizeCompat(0, 0),
newPreferredTileSize = IntSizeCompat(51, 51)
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.github.panpf.zoomimage.subsampling.internal.TileDecoder
import com.github.panpf.zoomimage.subsampling.internal.TileManager
import com.github.panpf.zoomimage.subsampling.internal.TileManager.Companion.DefaultPausedContinuousTransformTypes
import com.github.panpf.zoomimage.subsampling.internal.calculatePreferredTileSize
import com.github.panpf.zoomimage.subsampling.internal.checkNewPreferredTileSize
import com.github.panpf.zoomimage.subsampling.internal.decodeAndCreateTileDecoder
import com.github.panpf.zoomimage.subsampling.internal.toIntroString
import com.github.panpf.zoomimage.util.IntOffsetCompat
Expand All @@ -54,7 +55,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.abs
import kotlin.math.roundToInt

/**
Expand Down Expand Up @@ -280,26 +280,21 @@ class SubsamplingEngine(val zoomableEngine: ZoomableEngine) {
// View size animations cause frequent changes in viewSize, so a delayed reset avoids this problem
@Suppress("OPT_IN_USAGE")
zoomableEngine.containerSizeState.debounce(80).collect {
val oldPreferredTileSize = preferredTileSizeState.value
val newPreferredTileSize = calculatePreferredTileSize(it)
val preferredTileSize = preferredTileSizeState.value
val finalPreferredTileSize = if (preferredTileSize.isEmpty()) {
newPreferredTileSize
} else if (abs(newPreferredTileSize.width - preferredTileSize.width) >=
// When the width changes by more than 1x, the preferredTileSize is recalculated to reduce the need to reset the TileManager
preferredTileSizeState.value.width * (if (newPreferredTileSize.width > preferredTileSize.width) 1f else 0.5f)
) {
newPreferredTileSize
} else if (abs(newPreferredTileSize.height - preferredTileSize.height) >=
preferredTileSize.height * (if (newPreferredTileSize.height > preferredTileSize.height) 1f else 0.5f)
) {
// When the height changes by more than 1x, the preferredTileSize is recalculated to reduce the need to reset the TileManager
newPreferredTileSize
} else {
null
val checkPassed = checkNewPreferredTileSize(
oldPreferredTileSize = oldPreferredTileSize,
newPreferredTileSize = newPreferredTileSize
)
logger.d {
"SubsamplingEngine. reset preferredTileSize. " +
"oldPreferredTileSize=$oldPreferredTileSize, " +
"newPreferredTileSize=$newPreferredTileSize, " +
"checkPassed=$checkPassed. " +
"'${imageKey}'"
}
logger.d { "SubsamplingEngine. reset preferredTileSize. finalPreferredTileSize=$finalPreferredTileSize. '${imageKey}" }
if (finalPreferredTileSize != null) {
preferredTileSizeState.value = finalPreferredTileSize
if (checkPassed) {
preferredTileSizeState.value = newPreferredTileSize
}
}
}
Expand Down

0 comments on commit 78241d6

Please sign in to comment.