Search code examples
androidcrashout-of-memoryandroid-imageandroid-jetpack-compose

Handling java.lang.OutOfMemoryError with Image Loading in Android Compose using painterResource


I am encountering a recurring issue while working with the "Image" component in Android Compose. I am using the painterResource function to load images into the "Image" component. However, I'm facing frequent crashes related to java.lang.OutOfMemoryError.

I suspect that the crashes are occurring due to memory consumption associated with image loading. I would like to know the best practices and techniques to avoid these OutOfMemoryError crashes while using the "Image" component in Android Compose. Any insights into memory-efficient image loading strategies or other relevant optimizations would be greatly appreciated.

Thank you for your assistance in advance!

This is 1 of the crashes:

Fatal Exception: java.lang.OutOfMemoryError
Failed to allocate a 18195852 byte allocation with 10423024 free bytes and 9MB until OOM

dalvik.system.VMRuntime.newNonMovableArray (VMRuntime.java)
android.graphics.BitmapFactory.nativeDecodeAsset (BitmapFactory.java)
android.graphics.BitmapFactory.decodeStream (BitmapFactory.java:624)
android.graphics.BitmapFactory.decodeResourceStream (BitmapFactory.java:457)
android.graphics.drawable.Drawable.createFromResourceStream (Drawable.java:1152)
android.content.res.ResourcesImpl.createFromResourceStream (ResourcesImpl.java:1296)
android.content.res.ResourcesImpl.loadDrawableForCookie (ResourcesImpl.java:743)
android.content.res.ResourcesImpl.loadDrawable (ResourcesImpl.java:585)
android.content.res.MiuiResourcesImpl.loadDrawable (MiuiResourcesImpl.java:328)
android.content.res.Resources.getDrawable (Resources.java:785)
androidx.compose.ui.res.ImageResources_androidKt.imageResource (ImageResources.android.kt:39)
androidx.compose.ui.res.PainterResources_androidKt.loadImageBitmapResource (PainterResources.android.kt:109)
androidx.compose.ui.res.PainterResources_androidKt.access$loadImageBitmapResource (PainterResources.android.kt:1)
androidx.compose.ui.res.PainterResources_androidKt.painterResource (PainterResources.android.kt:70)
com.ui.screens.main.MainScreenKt$VipLevels$$inlined$ConstraintLayout$5.invoke (ConstraintLayout.kt:2308)
androidx.constraintlayout.compose.ConstraintLayoutKt$ConstraintLayout$2.invoke (ConstraintLayout.kt:470)
com.ui.screens.main.MainScreenKt$VipLevels$$inlined$ConstraintLayout$5.invoke (ConstraintLayout.kt:470)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:108)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:35)
androidx.compose.runtime.ComposablesKt.ReusableComposeNode (Composables.kt:373)
androidx.compose.ui.layout.LayoutKt.MultiMeasureLayout (Layout.kt:251)
androidx.constraintlayout.compose.ConstraintLayoutKt.ConstraintLayout (ConstraintLayout.kt:467)
com.ui.screens.main.MainScreenKt.VipLevels (MainScreen.kt:314)
com.ui.screens.main.MainScreenKt$MainScreen$$inlined$ConstraintLayout$5.invoke (ConstraintLayout.kt:2394)
androidx.constraintlayout.compose.ConstraintLayoutKt$ConstraintLayout$2.invoke (ConstraintLayout.kt:470)
com.ui.screens.main.MainScreenKt$MainScreen$$inlined$ConstraintLayout$5.invoke (ConstraintLayout.kt:470)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:108)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:35)
androidx.compose.runtime.ComposablesKt.ReusableComposeNode (Composables.kt:373)
androidx.compose.ui.layout.LayoutKt.MultiMeasureLayout (Layout.kt:251)
androidx.constraintlayout.compose.ConstraintLayoutKt.ConstraintLayout (ConstraintLayout.kt:467)
com.ui.screens.main.MainScreenKt.MainScreen (MainScreen.kt:127)
com.ui.screens.main.MainScreenRoute.Content (MainScreen.kt:69)
com.navigation.NavRoute$composable$1.invoke (NavRoute.kt:100)
com.navigation.NavRoute$composable$1.access$invoke$lambda$0 (NavRoute.kt:59)
com.navigation.NavRoute$composable$1.invoke (NavRoute.kt:59)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:117)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:35)
androidx.navigation.compose.NavHostKt$NavHost$4$2.invoke (NavHost.kt:173)
androidx.navigation.compose.NavHostKt$NavHost$4$2.invoke (NavHost.kt:172)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:108)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:35)
androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider (CompositionLocal.kt:248)
androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider (SaveableStateHolder.kt:84)
androidx.navigation.compose.NavBackStackEntryProviderKt.SaveableStateProvider (NavBackStackEntryProvider.kt:65)
androidx.navigation.compose.NavBackStackEntryProviderKt.access$SaveableStateProvider (NavBackStackEntryProvider.kt:1)
androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke (NavBackStackEntryProvider.kt:52)
androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke (NavBackStackEntryProvider.kt:51)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:108)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:35)
androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider (CompositionLocal.kt:228)
androidx.navigation.compose.NavBackStackEntryProviderKt.LocalOwnersProvider (NavBackStackEntryProvider.kt:47)
androidx.navigation.compose.NavHostKt$NavHost$4.invoke (NavHost.kt:172)
androidx.navigation.compose.NavHostKt$NavHost$4.invoke (NavHost.kt:146)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:117)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:35)
androidx.compose.animation.CrossfadeKt$Crossfade$5$1.invoke (Crossfade.kt:133)
androidx.compose.animation.CrossfadeKt$Crossfade$5$1.access$invoke$lambda$1 (Crossfade.kt:128)
androidx.compose.animation.CrossfadeKt$Crossfade$5$1.invoke (Crossfade.kt:128)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:108)
androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:35)
androidx.compose.animation.CrossfadeKt.Crossfade (Crossfade.kt:142)
androidx.compose.animation.CrossfadeKt.Crossfade (Crossfade.kt:73)
androidx.navigation.compose.NavHostKt.NavHost (NavHost.kt:146)
androidx.navigation.compose.NavHostKt$NavHost$5.invoke (NavHost.kt:2)
androidx.navigation.compose.NavHostKt$NavHost$5.invoke (NavHost.kt:1)
androidx.compose.runtime.RecomposeScopeImpl.compose (RecomposeScopeImpl.kt:192)
androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd (Composer.kt:2511)
androidx.compose.runtime.ComposerImpl.skipCurrentGroup (Composer.kt:2780)
androidx.compose.runtime.ComposerImpl.doCompose (Composer.kt:3259)
androidx.compose.runtime.ComposerImpl.recompose$runtime_release (Composer.kt:3210)
androidx.compose.runtime.CompositionImpl.recompose (Composition.kt:864)
androidx.compose.runtime.Recomposer.performRecompose (Recomposer.kt:1125)
androidx.compose.runtime.Recomposer.access$setCloseCause$p (Recomposer.kt:124)
androidx.compose.runtime.Recomposer.access$performRecompose (Recomposer.kt:124)
androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke (Recomposer.kt:580)
androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke (Recomposer.kt:548)
androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame (AndroidUiFrameClock.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch (AndroidUiDispatcher.android.kt:109)
androidx.compose.ui.platform.AndroidUiDispatcher.access$setScheduledFrameDispatch$p (AndroidUiDispatcher.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch (AndroidUiDispatcher.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame (AndroidUiDispatcher.android.kt:69)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:871)
android.view.Choreographer.doCallbacks (Choreographer.java:685)
android.view.Choreographer.doFrame (Choreographer.java:618)
android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:859)
android.os.Handler.handleCallback (Handler.java:754)
android.os.Handler.dispatchMessage (Handler.java:95)
android.os.Looper.loop (Looper.java:165)
android.app.ActivityThread.main (ActivityThread.java:6375)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:912)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:802)

Solution

  • SOLVED

    I use one size for all images. I moved all images from the "drawable" folder to the "drawable-nodpi" folder. It's possible that the system was attempting to scale the images to fit various screen sizes, and by doing this, the issue no longer occurs on some devices due to large image sizes.