【问题标题】:Exception handling - Android异常处理 - Android
【发布时间】:2014-03-12 23:29:44
【问题描述】:

我的应用有时会因 outOfMemoryError 而崩溃。我试图优雅地处理它而不是让应用程序崩溃。这是错误的 Logcat,然后是我的 try/catch 块:

EDIT 这个问题是关于异常处理的,不是有效地显示图像。我在加载时将图像采样到有效尺寸。但是在旧手机上它仍然可能崩溃,因为用户可以手动将图像添加到活动中。我想要一条消息说他们已经增加了他们的限制而不是崩溃。谢谢。

02-14 09:46:11.833: E/dalvikvm-heap(8495): Out of memory on a 2424016-byte allocation.
02-14 09:46:11.833: I/dalvikvm(8495): "main" prio=5 tid=1 RUNNABLE
02-14 09:46:11.833: I/dalvikvm(8495):   | group="main" sCount=0 dsCount=0 obj=0x40fc3508 self=0x40fb2ff8
02-14 09:46:11.833: I/dalvikvm(8495):   | sysTid=8495 nice=0 sched=0/0 cgrp=apps handle=1074818864
02-14 09:46:11.838: I/dalvikvm(8495):   | schedstat=( 10854840575 3262089934 15014 ) utm=971 stm=113 core=1
02-14 09:46:11.838: I/dalvikvm(8495):   at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
02-14 09:46:11.838: I/dalvikvm(8495):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:625)
02-14 09:46:11.838: I/dalvikvm(8495):   at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:478)
02-14 09:46:11.838: I/dalvikvm(8495):   at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:501)
02-14 09:46:11.838: I/dalvikvm(8495):   at com.btf271.imagehelper.ImageHelper.decodeSampledBitmapFromResource(ImageHelper.java:218)
02-14 09:46:11.838: I/dalvikvm(8495):   at com.btf271.multitouchimages.MultitouchImagesView$Img.load(MultitouchImagesView.java:285)
02-14 09:46:11.838: I/dalvikvm(8495):   at com.btf271.multitouchimages.MultitouchImagesView.loadImages(MultitouchImagesView.java:134)
02-14 09:46:11.838: I/dalvikvm(8495):   at com.btf271.fashionassistant.DressingRoomActivity.onResume(DressingRoomActivity.java:125)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1199)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.app.Activity.performResume(Activity.java:5280)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2629)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2667)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1279)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.os.Handler.dispatchMessage(Handler.java:99)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.os.Looper.loop(Looper.java:137)
02-14 09:46:11.843: I/dalvikvm(8495):   at android.app.ActivityThread.main(ActivityThread.java:4921)
02-14 09:46:11.843: I/dalvikvm(8495):   at java.lang.reflect.Method.invokeNative(Native Method)
02-14 09:46:11.843: I/dalvikvm(8495):   at java.lang.reflect.Method.invoke(Method.java:511)
02-14 09:46:11.843: I/dalvikvm(8495):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
02-14 09:46:11.843: I/dalvikvm(8495):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
02-14 09:46:11.843: I/dalvikvm(8495):   at dalvik.system.NativeStart.main(Native Method)
02-14 09:46:11.843: A/libc(8495): Fatal signal 11 (SIGSEGV) at 0x0000bed8 (code=1), thread 8495 (ashionassistant)
02-14 09:46:22.023: I/ActivityThread(8849): Pub com.btf271.ImageHelper.contentproviders.media: com.btf271.imagehelper.MediaContentProvider

导致错误的方法:MultitouchImagesView.loadImages(MultitouchImagesView.java:134):

/** Called by activity's onResume() method to load the images */
public void loadImages(Context context) {
    Resources res = context.getResources();
    int n = mImages.size();
    for (int i = 0; i < n; i++){
        try{
        mImages.get(i).load(res);
        }
        catch(OutOfMemoryError oom){
            Log.d("out of memory", "out of memory");
        }
        catch( Exception ex) {
            Log.d("general exception", ex.getMessage());
        }
    }
}

NKN 的回答解释了为什么它崩溃得很好。那么有解决办法吗?

有关该应用的更多信息。用户一次将一张图像添加到活动中,他们想要的图像数量不限。因此,我将在第 6 幅图像上加盖以避免 outOfMemory 异常。但是,我可以在每次将图像添加到活动时检查 outOfMemory 异常,以防万一,以防一部手机无法处理 6 张图像? (有些手机可以处理 30 张图片,但有些可能只能处理 6 张左右)。

【问题讨论】:

    标签: android exception-handling


    【解决方案1】:

    尽管有try/catch 块,它还是会崩溃,因为您的内存已经用完了。您的某些图像正在消耗您剩余的所有内存,当这种情况发生时,尽管您尝试处理它,但由于您没有任何可用内存,所以您的应用程序只会死掉。

    我会删除您的可绘制文件夹中的每张图片,然后逐张添加它们,这样您就可以轻松检测出令人痛苦的图片并正确管理它。我推荐阅读this

    【讨论】:

    • 谢谢,我已经阅读了您发布的课程。我不认为我可以删除图像并一张一张添加它们,因为它们有很多定位和尺寸信息需要在加载时保留。还有其他方法吗?
    • 您可以简单地复制您的可绘制文件夹,并将每个图像替换为与您要替换的图像同名的“虚拟”1Kb 图像。布局加载不正确没关系,只是为了调试。如果您一张一张替换图像,您将很快看到哪个产生了该 OOM 错误。
    • 嗯。我不确定这是否适用于我的应用程序。我认为您可能需要有关我的应用程序的更多信息。我以用户身份手动将图像添加到活动中。用户可以继续添加越来越多的内容,但我会在第 6 张图片上强制停止。但是由于每部手机都不同,我想在每次用户添加一部手机时检查是否有异常,以防万一他们无法制作 6 张图片。在我的情况下,您所说的是一种有效的方法吗?谢谢。
    • 用户一次添加一个。所以我确实知道是什么导致了异常。
    • 所以我更多地考虑在其他地方捕获错误,就像之前一样,这样的工作量要少得多。如果可能的话。谢谢
    【解决方案2】:

    尝试通过定义全局异常处理程序从内存中转储应用程序的垃圾

    public class MyUncaughtExceptionHandler implements
            Thread.UncaughtExceptionHandler {
    
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            if (ex.getClass().equals(OutOfMemoryError.class)) {
                try {
                    android.os.Debug.dumpHprofData("/sdcard/dump.hprof");
                } catch (IOException e) {
                    Log.d("SD ExceptionHandler", ex.getMessage().toString());
                }
            } else {
                Log.d("SD ExceptionHandler", ex.getMessage().toString());
            }
        }
    
    }
    

    然后在你的 Activity 的 onCreate 调用中:

    Thread.currentThread().setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
    

    【讨论】:

    • 谢谢。这段代码对我来说有点陌生,因为我是一名学生。我会逐字复制这个单词,甚至是“/sdcard/dump.hprof”吗?这段代码是否会从内存中转储垃圾,所以最好在我的每个活动的 onCreate() 中使用它?
    • 谢谢!我收到这个警告:不要硬编码“/sdcard/”;改用 Environment.getExternalStorageDirectory().getPath() 。我应该这样做吗?
    • 是的,这是一个更好的主意。但这只是一个警告;)
    • 谢谢。我收到另一个警告,当我调用它时应该以静态方式访问它。我最初有 Thread.currentT.... 然后我根据 Eclipse 的建议将其更改为 Thread.currentThread(); Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
    • 这对解决这个错误有帮助吗?
    【解决方案3】:

    您需要在清单中将此标志设置为应用程序属性:

    android:largeHeap="true"
    

    由于您的目标是 SDK 11 或更高版本,它应该可以工作。

    Android Heap memory increase

    【讨论】:

      【解决方案4】:

      位图占用大量内存,尤其是对于像这样的丰富图像 照片。例如,Galaxy Nexus 上的相机拍摄照片 高达 2592x1936 像素(5 兆像素)。如果位图配置 使用的是 ARGB_8888(从 Android 2.3 开始的默认值)然后 将此图像加载到内存中大约需要 19MB 内存(2592*1936*4 字节),立即耗尽某些设备上的每个应用程序的限制。

      http://developer.android.com/training/displaying-bitmaps/index.html

      您的内存不足是因为您没有仔细处理图像。请查看以下问题/答案,以更好地了解尝试加载图像时会发生什么:Strange out of memory issue while loading an image to a Bitmap object

      如果您是新开发人员,那么我建议您只使用可以为您加载部分的任何好的库,否则将很难加载图像。

      Android-Universal-Image-Loader:广泛使用的库https://github.com/nostra13/Android-Universal-Image-Loader

      替代毕加索图书馆:一行代码为您完成工作:http://square.github.io/picasso/

      【讨论】:

      • 人们一直认为我没有有效地显示位图,但我已经阅读了有关 Android 开发人员培训的文章并实施了这些技术。即使使用毕加索,我也会在用户添加大量图像后引发异常。我只需要异常处理来让他们知道他们何时添加了图像限制。任何手机都会在某个时候崩溃。谢谢
      • @user3164083 你知道我在一个活动中使用 Android-Universal-Image-Loader 处理了 1000 多张照片并且没有崩溃。
      • 这将是一个网格视图,我在这个应用程序中没有任何库就这样做了。我需要这些图像始终在此活动的内存中,因为它不是 grdview,它们永远不会离开屏幕。完全不同的故事。
      • 你可能会发现这个有用stackoverflow.com/questions/2679330/…
      • 谢谢,这很有用。我认为在我的场景中捕获错误很好,例如,当错误被抛出时 - 当用户添加了他们的图像限制时,不要添加会使应用程序崩溃的最后一个。也许毕加索会有所帮助,但我不明白为什么,当我已经对图像进行采样时,我无法回收它们或做任何类似的事情,因为它们留在屏幕上,所有可以做的就是采样。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-13
      • 2019-10-17
      • 2012-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多