When I try to render a big image (5312 x 2988), the image container just shows an empty box. If the image is reasonably sized (~1024x1024) or comes directly from device instead from a remote url, it renders fine. Not sure if it's a memory or networking issue. There's another open issue(https://github.com/facebook/react-native/issues/7408) that seems to discuss a similar topic.
Render a large image in a ListView. In a dev mode, the app will crash in a few seconds. In a production mode, the app just shows a white background in place of an image.
Inside a ListView I render an image like below:
<Image
source={{uri: imageURI}}
style={styles.canvas}
resizeMode="cover"
/> : null
StyleSheet.create({
canvas: {
width: null,
height: 300,
},
})
<ListView
dataSource={this.state.dataSource}
renderRow={this.onRenderRow}
enableEmptySections={true}
initialListSize={5}
pageSize={10}
/>
Image is rendered successfully.
Unfortunately, trying to resize a large picture using ImageEditor also fails because of an OutOfMemory exception. I used the photos that are captured by device's built-in camera.
10-20 16:38:47.511 19110 19154 E AndroidRuntime: FATAL EXCEPTION: AsyncTask #4
10-20 16:38:47.511 19110 19154 E AndroidRuntime: Process: com.kpopio, PID: 19110
10-20 16:38:47.511 19110 19154 E AndroidRuntime: java.lang.RuntimeException: An error occurred while executing doInBackground()
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at android.os.AsyncTask$3.done(AsyncTask.java:309)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at java.util.concurrent.FutureTask.run(FutureTask.java:242)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at java.lang.Thread.run(Thread.java:818)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: Caused by: java.lang.OutOfMemoryError: Failed to allocate a 63489036 byte allocation with 16777216 free bytes and 53MB until OOM
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:882)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:858)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at com.facebook.react.modules.camera.ImageEditingManager$CropTask.crop(ImageEditingManager.java:299)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at com.facebook.react.modules.camera.ImageEditingManager$CropTask.doInBackgroundGuarded(ImageEditingManager.java:270)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at com.facebook.react.modules.camera.ImageEditingManager$CropTask.doInBackgroundGuarded(ImageEditingManager.java:199)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:34)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:22)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at android.os.AsyncTask$2.call(AsyncTask.java:295)
10-20 16:38:47.511 19110 19154 E AndroidRuntime: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
References:
Hi,
I think the problem is the issue of memory ( I face same problem ). I am not sure but may be this is the reason that's why facebook send small images in device.
Yes. From looking at the source code, RN uses fresco to not load large images in memory for Image components' resizeMode. In this case, I assume that's not enough because the initial image is so big and I should resize it myself before trying to render it.
I would appreciate any advice/suggestion!
I mean, at some point this is expected, right? - there's only so large of an image that you will be able to display before running out of memory. I think you just have to plan to display a thumbnail rather than a whole image if the image is large enough. That's how the underlying Image class in Android works so I think you would have this same problem even if you were not using React Native.
I'm running into this too, and the images aren't crazy large at all, about 1000x1300.
The main issue is that it works on some devices but not others (and always works on iOS), but the onError handler is never invoked when it fails to render, just a blank box remains.
This means that we cannot have a graceful fallback to load a less detailed image - a thumbnail in my case is not sufficient since the entire purpose of the app is to display large images.
Can at least the onError be made work properly?
Making onError work properly seems like a good idea. Are you interested in putting together a pull request?
Unlikely to happen soon - I'm on Parental Leave until Jan, and my knowledge of Android is basically nil :-) But this is what we have an awesome team in MPK for, I'm sure someone like Tim Yung could knock this out in ten minutes ;-)
I've looked into this a bit, and it appears to be a widespread issue in the Android community.
The most promising doc I found is https://developer.android.com/training/displaying-bitmaps/load-bitmap.html , which suggests using the "inSampleSize" options when using the BitmapFactory to load an image. Unfortunately it looks like RN uses FBs own Fresco library to load it, which doesn't appear to use BitmapFactory, as best as I can quickly see.
Any thoughts on how to proceed? This is really a bad problem, any app that wants to show a gallery of non blurry, downsampled images is basically impossible.
I'm excited that you are investigating this during your parental leave ;-) Maybe @mkonicek has an idea for how to proceed here.
My guess is that it's related to these lines
https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java#L372-L379
It only decided to do a resize if it's a local image (ReactImageView.shouldResize()). Android docs mention that if you do a resize before display, it uses less memory, but RN doesn't.
Thoughts?
@lacker @shaneosullivan Hey! OP here. I found that <Image /> components crash the app with an OutOfMemory exception iff you try to render a _big_ image component with an image source that's _sufficiently large_.

Like in @shaneosullivan's comment, I assumed this happens because FB's fresco tries to load big images into memory before resizing and rendering it. So I wrote a simple native module that resizes large images before rendering them. It uses inSampleSize to not load large images into memory while resizing them to avoid throwing exception. For me, this solution worked well but I'm not sure if this can be applied to all cases.
Also, I'd be happy to help resolve this issue! I can start with a small PR that makes onError work.
@woniesong92 Hey that is awesome that you can help resolve this! Making onError work seems like a straightforward step that makes this better. If we change the default image behavior in a more complicated way, it might have more tradeoffs, but I don't see why not to fix onError. If you ping me on the pull request & tag this issue then I will help make sure it gets reviewed.
@lacker , getting onError to work is a good first step. However this is a fundamental failing in React Native, that it cannot display reasonable sized images on Android when other similar code can do it just fine.
Is there a way to escalate this internally? If we were using RN for our photo viewer this would be a UBN....
@shaneosullivan The internal consensus is that you should fix it 馃槣
@lacker , surprising that :-) I'll happily swap you some fun Ads front end tasks that totally rewrite some of the logic core to everything we use to make money. Let's see which of us breaks the most stuff fastest :-) (hint: probably me)
Has there been any progress on this?
android:largeHeap="true" fixed the problem for our use cases (per https://github.com/facebook/react-native/issues/13600)
Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!
If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:
If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.
This issue still needs fixing in RN 0.46.4. It fails with images not that big (< 1600px on one side)
Edit: Actually, when dealing with large images and using resizeMethod=resize all looks fine. The problem is that the heuristics the docs talk about happen in this piece of code and that's a check for local files.
Genymotion Google Galaxy Nexus (API Level 16) - remote image not loading, works fine on iOS; resizeMethod={'resize'} doesn't work.
Most helpful comment
Has there been any progress on this?