Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
364 views
in Technique[技术] by (71.8m points)

android - galaxy s4 and maybe all HD phones? out of memory error inflating layout

So this app I am working on, works just fine on a really old miserable Android 2.3.3 phone. However when running it on the GS4, the GS4 is throwing out of memory exceptions every time is has to load a resource from the drawables, that is predefined in the xml.

<ImageView
        android:id="@+id/ivLearnMore"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_weight="1"
        android:scaleType="fitCenter"
        android:src="@drawable/learn_more" />

For example this Imageview will throw an exception when inflating the layout because it already has an image assigned. (256x256)

what is going on?

05-08 10:33:54.972: E/dalvikvm-heap(24423): Out of memory on a 16777232-byte allocation.
05-08 10:33:54.972: I/dalvikvm(24423): "main" prio=5 tid=1 RUNNABLE
05-08 10:33:54.972: I/dalvikvm(24423):   | group="main" sCount=0 dsCount=0 obj=0x41187b38 self=0x40dd1b68
05-08 10:33:54.972: I/dalvikvm(24423):   | sysTid=24423 nice=0 sched=0/0 cgrp=apps handle=1074533852
05-08 10:33:54.972: I/dalvikvm(24423):   | state=R schedstat=( 0 0 0 ) utm=147 stm=1265 core=0
05-08 10:33:54.972: I/dalvikvm(24423):   at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:596)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:817)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.content.res.Resources.loadDrawable(Resources.java:2854)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.view.View.<init>(View.java:3460)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.view.ViewGroup.<init>(ViewGroup.java:446)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.widget.LinearLayout.<init>(LinearLayout.java:176)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.widget.LinearLayout.<init>(LinearLayout.java:172)
05-08 10:33:54.972: I/dalvikvm(24423):   at java.lang.reflect.Constructor.constructNative(Native Method)
05-08 10:33:54.972: I/dalvikvm(24423):   at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.view.LayoutInflater.createView(LayoutInflater.java:593)
05-08 10:33:54.972: I/dalvikvm(24423):   at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.view.LayoutInflater.onCreateView(LayoutInflater.java:666)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:691)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.view.LayoutInflater.inflate(LayoutInflater.java:467)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
05-08 10:33:54.972: I/dalvikvm(24423):   at com.travelstorysgps.travelstorys.FragmentInfo.onCreateView(FragmentInfo.java:54)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.support.v4.app.Fragment.performCreateView(Fragment.java:1460)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:911)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.os.Handler.handleCallback(Handler.java:725)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.os.Handler.dispatchMessage(Handler.java:92)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.os.Looper.loop(Looper.java:137)
05-08 10:33:54.972: I/dalvikvm(24423):   at android.app.ActivityThread.main(ActivityThread.java:5293)
05-08 10:33:54.972: I/dalvikvm(24423):   at java.lang.reflect.Method.invokeNative(Native Method)
05-08 10:33:54.972: I/dalvikvm(24423):   at java.lang.reflect.Method.invoke(Method.java:511)
05-08 10:33:54.972: I/dalvikvm(24423):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
05-08 10:33:54.972: I/dalvikvm(24423):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
05-08 10:33:54.972: I/dalvikvm(24423):   at dalvik.system.NativeStart.main(Native Method)
05-08 10:33:54.972: D/skia(24423): --- decoder->decode returned false
05-08 10:33:54.972: D/AndroidRuntime(24423): Shutting down VM
05-08 10:33:54.972: W/dalvikvm(24423): threadid=1: thread exiting with uncaught exception (group=0x41186ac8)
05-08 10:33:54.992: E/AndroidRuntime(24423): FATAL EXCEPTION: main
05-08 10:33:54.992: E/AndroidRuntime(24423): android.view.InflateException: Binary XML file line #2: Error inflating class <unknown>
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.LayoutInflater.createView(LayoutInflater.java:619)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:666)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:691)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.LayoutInflater.inflate(LayoutInflater.java:467)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at com.travelstorysgps.travelstorys.FragmentInfo.onCreateView(FragmentInfo.java:54)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1460)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:911)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.os.Handler.handleCallback(Handler.java:725)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.os.Handler.dispatchMessage(Handler.java:92)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.os.Looper.loop(Looper.java:137)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.app.ActivityThread.main(ActivityThread.java:5293)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at java.lang.reflect.Method.invokeNative(Native Method)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at java.lang.reflect.Method.invoke(Method.java:511)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at dalvik.system.NativeStart.main(Native Method)
05-08 10:33:54.992: E/AndroidRuntime(24423): Caused by: java.lang.reflect.InvocationTargetException
05-08 10:33:54.992: E/AndroidRuntime(24423):    at java.lang.reflect.Constructor.constructNative(Native Method)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.LayoutInflater.createView(LayoutInflater.java:593)
05-08 10:33:54.992: E/AndroidRuntime(24423):    ... 21 more
05-08 10:33:54.992: E/AndroidRuntime(24423): Caused by: java.lang.OutOfMemoryError
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:596)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:817)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.content.res.Resources.loadDrawable(Resources.java:2854)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.View.<init>(View.java:3460)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.view.ViewGroup.<init>(ViewGroup.java:446)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.widget.LinearLayout.<init>(LinearLayout.java:176)
05-08 10:33:54.992: E/AndroidRuntime(24423):    at android.widget.LinearLayout.<init>(LinearLayout.java:172)
05-08 10:33:54.992: E/AndroidRuntime(24423):    ... 24 more

Here is a exception from a different screen

05-08 10:35:29.565: E/dalvikvm-heap(24774): Out of memory on a 16777232-byte allocation.
05-08 10:35:29.565: I/dalvikvm(24774): "main" prio=5 tid=1 RUNNABLE
05-08 10:35:29.565: I/dalvikvm(24774):   | group="main" sCount=0 dsCount=0 obj=0x41187b38 self=0x40dd1b68
05-08 10:35:29.565: I/dalvikvm(24774):   | sysTid=24774 nice=0 sched=0/0 cgrp=apps handle=1074533852
05-08 10:35:29.565: I/dalvikvm(24774):   | state=R schedstat=( 0 0 0 ) utm=175 stm=2086 core=1
05-08 10:35:29.565: I/dalvikvm(24774):   at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:596)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:817)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.content.res.Resources.loadDrawable(Resources.java:2854)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.view.View.<init>(View.java:3460)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.view.ViewGroup.<init>(ViewGroup.java:446)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.widget.LinearLayout.<init>(LinearLayout.java:176)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.widget.LinearLayout.<init>(LinearLayout.java:172)
05-08 10:35:29.565: I/dalvikvm(24774):   at java.lang.reflect.Constructor.constructNative(Native Method)
05-08 10:35:29.565: I/dalvikvm(24774):   at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
05-08 10:35:29.565: I/dalvikvm(24774):   at android.view.LayoutInflater.createView(LayoutInflater.java:593)
05-08 10:35:29.565: I/dalvikvm(24774):   at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
05-08 10:35:29.565: I/dalvikvm(24774): 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

(@Arash's answer provides a workaround, but this is my attempt to explain why it may work.)

So you have a rather big image in the drawable resource directory, you reference it in your layout xml file, and get an out of memory error at runtime when inflating it.

When loading drawable resources, Android will perform some pre-scaling if it deems it necessary. From the official documentation:

Based on the density of the current screen, the system uses any size- or density-specific resources from your application and displays them without scaling. If resources are not available in the correct density, the system loads the default resources and scales them up or down as needed to match the current screen's density. The system assumes that default resources (those from a directory without configuration qualifiers) are designed for the baseline screen density (mdpi), unless they are loaded from a density-specific resource directory.

This means 2 things:

  1. If there's no resource of the density of the environment the application is currently running on, the system will take a resource of another density and scale it (up or down) to match the target density
  2. Resources put in the drawable directory are assumed to be targeting an mdpi density

So you're currently running on an xxhdpi phone. The system wants to load the learn_more drawable resource to paint it on the ivLearnMore widget. It will look for it in the drawable-xxhdpi in priority but won't find it there, so will take the closest one it finds, in this case the one in the drawable directory (which it assumes to be targeting mdpi density), and load it into memory scaling it by a factor of 3 which is a lot if your image file was significantly big and can easily require more memory than is available to the application (and cause an out of memory error).

This is also why it loaded fine on your old crappy 2.3 device: the device was most likely of mdpi or hdpi density and the system didn't try to upscale it or did it by a factor of only 1.5.

The main thing here being that you put a resource suitable for an xxhdpi (or more ?) density in an mdpi directory.

So you have several options:

  1. provide one resource appropriately sized per density (i.e. one in each drawable-* directory): this is the best to avoid any problem, when possible
  2. if you only have one version of the resource, put it in the directory matching its density (drawable being equivalent to drawable-mdpi!), in your case maybe drawable-xxhdpi (depends on your resource)
  3. put the resource in the drawable-nodpi directory, this will prevent the system from performing any pre-scaling of the resource (but this is typically for density-agnostic resources e.g. which you resize yourself at runtime)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...