Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(image): [android] adding only-if-cached cache control option #47348

Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/react-native/Libraries/Image/ImageSource.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export interface ImageURISource {
* to a URL load request, no attempt is made to load the data from the originating source,
* and the load is considered to have failed.
*
* @platform ios (for `force-cache` and `only-if-cached`)
* @platform ios (for `force-cache`)
*/
cache?: 'default' | 'reload' | 'force-cache' | 'only-if-cached' | undefined;
/**
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native/Libraries/Image/ImageSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export interface ImageURISource {
* to a URL load request, no attempt is made to load the data from the originating source,
* and the load is considered to have failed.
*
* @platform ios (for `force-cache` and `only-if-cached`)
* @platform ios (for `force-cache`)
*/
+cache?: ?('default' | 'reload' | 'force-cache' | 'only-if-cached');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,11 @@ public enum class ImageCacheControl {
* be used to satisfy a URL load request.
*/
RELOAD,
/**
* The existing cache data will be used to satisfy a request, regardless of
* its age or expiration date. If there is no existing data in the cache corresponding
* to a URL load request, no attempt is made to load the data from the originating source,
* and the load is considered to have failed.
*/
ONLY_IF_CACHED,
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ internal class ReactOkHttpNetworkFetcher(private val okHttpClient: OkHttpClient)
ImageCacheControl.RELOAD -> {
cacheControlBuilder.noCache()
}
ImageCacheControl.ONLY_IF_CACHED -> {
cacheControlBuilder.onlyIfCached()
}
ImageCacheControl.DEFAULT -> {
// No-op
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ import android.graphics.Shader.TileMode
import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.net.Uri
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.common.references.CloseableReference
import com.facebook.common.util.UriUtil
import com.facebook.datasource.DataSource
import com.facebook.datasource.BaseDataSubscriber
import com.facebook.datasource.DataSubscriber
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder
import com.facebook.drawee.controller.ControllerListener
Expand Down Expand Up @@ -311,6 +315,7 @@ public class ReactImageView(
null,
"default" -> ImageCacheControl.DEFAULT
"reload" -> ImageCacheControl.RELOAD
"only-if-cached" -> ImageCacheControl.ONLY_IF_CACHED
else -> ImageCacheControl.DEFAULT
}
}
Expand Down Expand Up @@ -439,6 +444,38 @@ public class ReactImageView(
imagePipeline.evictFromCache(uri)
}

if (cacheControl == ImageCacheControl.ONLY_IF_CACHED) {
val imagePipeline = Fresco.getImagePipeline()
val dataSource = imagePipeline.isInDiskCache(uri)
Abbondanzo marked this conversation as resolved.
Show resolved Hide resolved

dataSource.subscribe(object : BaseDataSubscriber<Boolean>() {
override fun onNewResultImpl(dataSource: DataSource<Boolean>) {
if (!dataSource.isFinished()) return

val isInCache: Boolean = dataSource.getResult() ?: false

if (isInCache) {
setupImageRequest(uri, cacheControl, postprocessor, resizeOptions)
Abbondanzo marked this conversation as resolved.
Show resolved Hide resolved
}

dataSource.close()
}

override fun onFailureImpl(dataSource: DataSource<Boolean>) {}
}, CallerThreadExecutor.getInstance())

return
}

setupImageRequest(uri, cacheControl, postprocessor, resizeOptions)
}

private fun setupImageRequest(
uri: Uri,
cacheControl: ImageCacheControl,
postprocessor: Postprocessor?,
resizeOptions: ResizeOptions?
) {
val imageRequestBuilder =
ImageRequestBuilder.newBuilderWithSource(uri)
.setPostprocessor(postprocessor)
Expand Down
20 changes: 17 additions & 3 deletions packages/rn-tester/js/examples/Image/ImageExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,19 @@ function CacheControlAndroidExample(): React.Node {
key={reload}
/>
</View>
<View style={styles.leftMargin}>
<RNTesterText style={styles.resizeModeText}>
Only-if-cached
</RNTesterText>
<Image
source={{
uri: fullImage.uri + '?cacheBust=only-if-cached',
cache: 'only-if-cached',
}}
style={styles.base}
key={reload}
/>
</View>
</View>

<View style={styles.horizontal}>
Expand Down Expand Up @@ -1091,9 +1104,10 @@ exports.examples = [
},
{
title: 'Cache Policy',
description: ('First image will be loaded and will be cached. ' +
'Second image is the same but will be reloaded if re-rendered ' +
'as the cache policy is set to reload.': string),
description: `- First image will be loaded and cached.
- Second image is the same but will be reloaded if re-rendered as the cache policy is set to reload.
- Third image will never be loaded as the cache policy is set to only-if-cached and the image has not been loaded before.
`,
render: function (): React.Node {
return <CacheControlAndroidExample />;
},
Expand Down
Loading