Skip to content

Commit 1219729

Browse files
authored
Merge pull request #442 from noma4i/fix/android-skip-unchanged-image-reload
fix(android): avoid redundant image reloads
2 parents 21e8a17 + 13a92b5 commit 1219729

3 files changed

Lines changed: 81 additions & 5 deletions

File tree

android/src/main/java/com/turboimage/TurboImageListener.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import com.turboimage.events.FailureEvent
1111
import com.turboimage.events.StartEvent
1212
import com.turboimage.events.SuccessEvent
1313

14-
class TurboImageListener(private val view: TurboImageView) : ImageRequest.Listener {
14+
class TurboImageListener(
15+
private val view: TurboImageView,
16+
private val loadSignature: String
17+
) : ImageRequest.Listener {
1518

1619
override fun onStart(request: ImageRequest) {
1720
super.onStart(request)
@@ -28,6 +31,7 @@ class TurboImageListener(private val view: TurboImageView) : ImageRequest.Listen
2831

2932
override fun onSuccess(request: ImageRequest, result: SuccessResult) {
3033
super.onSuccess(request, result)
34+
view.markLoadSuccess(loadSignature)
3135

3236
val reactContext = view.context as ReactContext
3337
UIManagerHelper.getEventDispatcher(reactContext, view.id)?.let {
@@ -51,6 +55,7 @@ class TurboImageListener(private val view: TurboImageView) : ImageRequest.Listen
5155

5256
override fun onError(request: ImageRequest, result: ErrorResult) {
5357
super.onError(request, result)
58+
view.markLoadFailure(loadSignature)
5459

5560
val reactContext = view.context as ReactContext
5661
UIManagerHelper.getEventDispatcher(reactContext, view.id)?.let {

android/src/main/java/com/turboimage/TurboImageView.kt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,65 @@ class TurboImageView(private val reactContext: ThemedReactContext) :
5353
}
5454

5555
var memoryCacheKey: String? = null
56+
private var activeLoadSignature: String? = null
57+
private var lastSuccessfulLoadSignature: String? = null
58+
59+
fun shouldSkipReload(loadSignature: String): Boolean {
60+
return lastSuccessfulLoadSignature == loadSignature
61+
}
62+
63+
fun markLoadStarted(loadSignature: String) {
64+
activeLoadSignature = loadSignature
65+
}
66+
67+
fun markLoadSuccess(loadSignature: String) {
68+
if (activeLoadSignature == loadSignature) {
69+
lastSuccessfulLoadSignature = loadSignature
70+
activeLoadSignature = null
71+
}
72+
}
73+
74+
fun markLoadFailure(loadSignature: String) {
75+
if (activeLoadSignature == loadSignature) {
76+
lastSuccessfulLoadSignature = null
77+
activeLoadSignature = null
78+
}
79+
}
80+
81+
fun resetLoadSignature() {
82+
activeLoadSignature = null
83+
lastSuccessfulLoadSignature = null
84+
}
85+
86+
fun buildLoadSignature(defaultCrossfade: Int): String {
87+
val headersSignature = headers?.names()?.sorted()?.joinToString(",") { name ->
88+
"$name=${headers?.values(name)?.joinToString(";")}"
89+
} ?: ""
90+
val indicatorSignature = indicator.entries.sortedBy { it.key }.joinToString(",") { (key, value) ->
91+
"$key=$value"
92+
}
93+
val viewSizeSignature = if (resize == null) "${width}x${height}" else ""
94+
return listOf(
95+
uri,
96+
headersSignature,
97+
cacheKey,
98+
cachePolicy,
99+
crossfade ?: defaultCrossfade,
100+
blurhash,
101+
thumbhash,
102+
memoryCacheKey,
103+
indicatorSignature,
104+
showPlaceholderOnFailure,
105+
resize,
106+
viewSizeSignature,
107+
rounded,
108+
blur,
109+
monochrome,
110+
tint,
111+
allowHardware,
112+
format
113+
).joinToString("|") { it?.toString() ?: "" }
114+
}
56115

57116
val circleProgressDrawable: CircularProgressDrawable?
58117
get() {

android/src/main/java/com/turboimage/TurboImageViewManager.kt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,28 @@ class TurboImageViewManager : SimpleViewManager<TurboImageView>(), LifecycleEven
5454

5555
override fun onAfterUpdateTransaction(view: TurboImageView) {
5656
super.onAfterUpdateTransaction(view)
57-
reloadImage(view)
57+
reloadImage(view, force = false)
5858
}
5959

6060
override fun onDropViewInstance(view: TurboImageView) {
6161
super.onDropViewInstance(view)
62+
view.resetLoadSignature()
6263
view.dispose()
6364
}
6465

65-
private fun reloadImage(view: TurboImageView) {
66+
private fun reloadImage(view: TurboImageView, force: Boolean) {
6667
val defaultCrossfade = if (view.thumbhashDrawable != null || view.blurhashDrawable != null) {
6768
0
6869
} else {
6970
CrossfadeDrawable.DEFAULT_DURATION
7071
}
72+
val loadSignature = view.buildLoadSignature(defaultCrossfade)
73+
74+
if (!force && view.shouldSkipReload(loadSignature)) {
75+
return
76+
}
77+
78+
view.markLoadStarted(loadSignature)
7179

7280
val okHttpClient = OkHttpClient.Builder()
7381
.addInterceptor(ProgressInterceptor(object : ProgressListener {
@@ -86,6 +94,7 @@ class TurboImageViewManager : SimpleViewManager<TurboImageView>(), LifecycleEven
8694
.build()
8795

8896
val imageLoader = Coil.imageLoader(view.context).newBuilder()
97+
.networkObserverEnabled(false)
8998
.respectCacheHeaders(view.cachePolicy == "urlCache")
9099
.okHttpClient(okHttpClient)
91100
.build()
@@ -97,7 +106,7 @@ class TurboImageViewManager : SimpleViewManager<TurboImageView>(), LifecycleEven
97106
diskCacheKey(it)
98107
}
99108
view.allowHardware?.let { allowHardware(it) }
100-
listener(TurboImageListener(view))
109+
listener(TurboImageListener(view, loadSignature))
101110
view.format?.let {
102111
when (it) {
103112
"svg" -> {
@@ -253,16 +262,19 @@ class TurboImageViewManager : SimpleViewManager<TurboImageView>(), LifecycleEven
253262

254263
override fun onHostResume() {
255264
if (isInBackground) {
256-
reloadImage(imageView)
265+
reloadImage(imageView, force = true)
266+
isInBackground = false
257267
}
258268
}
259269

260270
override fun onHostPause() {
271+
imageView.resetLoadSignature()
261272
imageView.dispose()
262273
isInBackground = true
263274
}
264275

265276
override fun onHostDestroy() {
277+
imageView.resetLoadSignature()
266278
imageView.dispose()
267279
}
268280
}

0 commit comments

Comments
 (0)