Android アプリが OutOfMemory で落ちるときに確認を忘れがちなこと -> Bitmapのサイズ, src, View.INVISIBLE
確認した端末の環境
- Galaxy S6
- Android 6.0
- 普段の空きメモリ 600m くらい
結論
- 動的にリソース指定する ImageView に レイアウトしやすいからって xml 上の src に画像指定しない
アプリの内容と状況
- 大体全画面くらいのサイズの画像を2枚 ViewPager で 1枚ずつ全画面表示するタイミングがある
- Gallary のような。
- 今後増えるので ViewPager を使用
- 全画面大の画像は1枚あたりのサイズ 450k, 700k の png
- 80k と 370 k の png があるページを足したら OutOfMemoryError が出るようになった
- ViewPager での画像読み込みは Picasso 使用
当時の苦しみ
- 全画面で表示したいので小さいサイズで読み込めない
- そもそも 数百k 単位の画像数枚で OOM にまでなる ? 全部足しても 1.6m くらいなのに …
- 全画面大の画像はファイルサイズ最大 700k だったけど View に入った Bitmap は 64m
- bitmap だから当たり前だけど忘れていた…
作業内容
ログが長いので先に修正点から。 Android Studio の Android Monitor -> Monitors タブで確認 - 80k, 370k の画像をとりあえず 30k と 90k に -> 最初のこのベージすら表示できなかったものがまずは表示できるように。 全画面の画像も読み込んで最大 220m allocated. - ViewPager で表示する fragment の Layout XML の Image View の src に 700k の png を指定していた -> もちろん画像は動的に java 側で指定しているので外した。外すだけで allocated 最大 160m. - 80k, 370k の画像は表示し終わったら非表示にするので View に setImageResource(0) 指定 -> allocated 160m で変わらず。 - 80k, 370k の画像は表示し終わったら非表示にするので View に setVisibility(View.INVISIBLE) を指定していたので View.GONE に変更 -> allocated のサイズは変わらず 160m
Log
80k と 370 k の画像のページから既に表示できない
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example, PID: 22875 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.MainActivity}: android.view.InflateException: Binary XML file line #14: Binary XML file line #17: Error inflating class <unknown> at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3254) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) at android.app.ActivityThread.access$1100(ActivityThread.java:222) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:158) at android.app.ActivityThread.main(ActivityThread.java:7237) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: android.view.InflateException: Binary XML file line #14: Binary XML file line #17: Error inflating class <unknown> at android.view.LayoutInflater.inflate(LayoutInflater.java:551) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at android.view.LayoutInflater.inflate(LayoutInflater.java:380) at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:474) at android.app.Activity.setContentView(Activity.java:2387) at com.example.MainActivity.onCreate(MainActivity.java:45) at android.app.Activity.performCreate(Activity.java:6876) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) at android.app.ActivityThread.access$1100(ActivityThread.java:222) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:158) at android.app.ActivityThread.main(ActivityThread.java:7237) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: android.view.InflateException: Binary XML file line #17: Error inflating class <unknown> at android.view.LayoutInflater.createView(LayoutInflater.java:657) at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:706) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:774) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1001) at android.view.LayoutInflater.rInflate(LayoutInflater.java:843) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.inflate(LayoutInflater.java:527) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at android.view.LayoutInflater.inflate(LayoutInflater.java:380) at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:474) at android.app.Activity.setContentView(Activity.java:2387) at com.example.MainActivity.onCreate(MainActivity.java:45) at android.app.Activity.performCreate(Activity.java:6876) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) at android.app.ActivityThread.access$1100(ActivityThread.java:222) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:158) at android.app.ActivityThread.main(ActivityThread.java:7237) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.newInstance(Native Method) at android.view.LayoutInflater.createView(LayoutInflater.java:631) at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:706) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:774) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1001) at android.view.LayoutInflater.rInflate(LayoutInflater.java:843) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.inflate(LayoutInflater.java:527) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at android.view.LayoutInflater.inflate(LayoutInflater.java:380) at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:474) at android.app.Activity.setContentView(Activity.java:2387) at com.example.MainActivity.onCreate(MainActivity.java:45) at android.app.Activity.performCreate(Activity.java:6876) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) at android.app.ActivityThread.access$1100(ActivityThread.java:222) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:158) at android.app.ActivityThread.main(ActivityThread.java:7237) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: java.lang.OutOfMemoryError: Failed to allocate a 200450764 byte allocation with 16765264 free bytes and 140MB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:856) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:675) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:2228) at android.content.res.Resources.loadDrawableForCookie(Resources.java:4215) at android.content.res.Resources.loadDrawable(Resources.java:4089) at android.content.res.Resources.loadDrawable(Resources.java:3939) at android.content.res.TypedArray.getDrawable(TypedArray.java:886) at android.widget.ImageView.<init>(ImageView.java:157) at android.widget.ImageView.<init>(ImageView.java:145) at android.widget.ImageView.<init>(ImageView.java:141) at java.lang.reflect.Constructor.newInstance(Native Method) at android.view.LayoutInflater.createView(LayoutInflater.java:631) at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:706) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:774) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1001) at android.view.LayoutInflater.rInflate(LayoutInflater.java:843) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.inflate(LayoutInflater.java:527) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at android.view.LayoutInflater.inflate(LayoutInflater.java:380) at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:474) at android.app.Activity.setContentView(Activity.java:2387) at com.example.MainActivity.onCreate(MainActivity.java:45) at android.app.Activity.performCreate(Activity.java:6876) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) at android.app.ActivityThread.access$1100(ActivityThread.java:222) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:158) at android.app.ActivityThread.main(ActivityThread.java:7237) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) I/System.out: (HTTPLog)-Static: isSBSettingEnabled false I/System.out: (HTTPLog)-Static: isSBSettingEnabled false