内存不足异常,处理位图时

时间:2011-12-23 07:53:38

标签: java android

我正在开发一个应用程序,我可以为SlideShows异步下载图像。一个SlideShow包含10张幻灯片,因此在打开幻灯片时会下载10张图像。在我滚动浏览10-15张幻灯片后,我开始收到内存警告并跟踪跟踪和应用程序崩溃中的异常。

这是跟踪:

12-23 12:23:53.124: ERROR/dalvikvm-heap(3067): 45850-byte external allocation too large for this process.
12-23 12:23:53.134: ERROR/dalvikvm(3067): Out of memory: Heap Size=13127KB, Allocated=11913KB, Bitmap Size=11407KB
12-23 12:23:53.134: ERROR/GraphicsJNI(3067): VM won't let us allocate 45850 bytes
12-23 12:23:53.134: DEBUG/skia(3067): --- decoder->decode returned false
12-23 12:23:53.134: WARN/dalvikvm(3067): threadid=46: thread exiting with uncaught exception (group=0x400259f8)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): FATAL EXCEPTION: Thread-1016
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
12-23 12:23:53.134: ERROR/AndroidRuntime(3067):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:468)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:332)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067):     at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067):     at com.nbcu.myApp.appsupport.AsyncImageLoader.loadImageFromUrl(AsyncImageLoader.java:98)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067):     at com.nbcu.myApp.appsupport.AsyncImageLoader$2.run(AsyncImageLoader.java:70)
12-23 12:23:53.154: WARN/ActivityManager(96):   Force finishing activity com.nbcu.myApp.activities/com.nbcu.myApp.controllers.StoriesListController
12-23 12:23:53.224: ERROR/dalvikvm-heap(3067): 45850-byte external allocation too large for this process.
12-23 12:23:53.234: DEBUG/SurfaceFlinger(96): Layer::setBuffers(this=0x2fabc0), pid=96, w=1, h=1
12-23 12:23:53.234: ERROR/dalvikvm(3067): Out of memory: Heap Size=13127KB, Allocated=11948KB, Bitmap Size=11407KB
12-23 12:23:53.234: ERROR/GraphicsJNI(3067): VM won't let us allocate 45850 bytes
12-23 12:23:53.234: ERROR/Error(3067): Message = java.lang.OutOfMemoryError: bitmap size exceeds VM budget

正在下载图像的代码是:

public void run() {

        Looper.prepare();
        for (int i = 0; i < slides.size(); i++) {
            try {

                final SlideShowItem story = slides.get(i);
                if (story.getImage() == null) {
                    Drawable cachedImage = Utils.database.getRSSImage(Constants.StoriesTable, story.getItemId());

                    if (cachedImage != null) {
                        story.setImage(cachedImage);

                    } else {
                        cachedImage = asyncImageLoader.loadDrawable(story.getImagePath(), new ImageCallback() {
                            public void imageLoaded(Drawable imageDrawable, String imageUrl) {


                                story.setImage(imageDrawable);
                                Utils.database.storeRSSItemImage(Constants.StoriesTable, imageDrawable, story.getItemId());
                            }
                        });
                    }
                }

                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Looper.loop();
    }

loadDrawable()的代码是:

public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {

    final Handler handler = new Handler() {

        public void handleMessage(Message message) {

            imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
        }
    };
    new Thread() {

        public void run() {

                Drawable drawable = loadImageFromUrl(imageUrl);
                // System.out.println("image url: " + imageUrl);
                if (drawable != null)
                {
                    Message message = handler.obtainMessage(0, drawable);
                    handler.sendMessage(message);
                }
        }

    }.start();
    return null;
}

和loadImageFromURL()的代码是:

  public static Drawable loadImageFromUrl(String url) {

    Drawable image = null;

    try {
        InputStream in = (java.io.InputStream) new java.net.URL(url).getContent();
        if (in != null) {
            image = Drawable.createFromStream(in, "image");
        }
        in.close();

    } catch (Exception ex) {
        // ex.printStackTrace();
        Log.v("Exception ", "Asyn Image.In LoadImageFromURL Message: " + ex.toString());

    }
    return image;
}

下载图像后,它们会被缓存。我无法找到解决方法来避免此异常。可能是什么原因?当活动被破坏但我没有为我做任何事情时,我也尝试将图像视图设置为null?任何帮助表示赞赏。提前致谢。

3 个答案:

答案 0 :(得分:5)

Android是一款移动操作系统。它的内存有限,因此,您无法缓存所有slides.size()。我假设尺寸&gt; 15.例如,即时运行FastCV算法,高清图像作为标记,250000 x 180000像素,如果我在电脑上运行程序,工作正常,如果我在手机上这样做,不要,因为内存不够。

我认为你可以解决问题,如果只有caché10 - 15图像,取决于它们的大小。如果滚动,则在已使用的内存中缓存新的。

答案 1 :(得分:4)

考虑将缓存的图像缩小到与它们一起使用的视图的大小。例如,您可以在loadImageFromUrl(String url)方法中使用以下方法:

// Determining the original size of the image:
BitmapFactory.Options optnsSizeOnly = new BitmapFactory.Options();
optnsSizeOnly.inJustDecodeBounds = true;
InputStream inputStreamSizeOnly = (java.io.InputStream) new java.net.URL(url).getContent();
BitmapFactory.decodeStream(inputStreamSizeOnly, null, optnsSizeOnly);
int widthOriginal = optnsSizeOnly.outWidth;

// Determining the scale ratio.
// Note, it's just an example, you should use more sophisticated algorithm:
int ratio = widhtOriginal / widthView; // widthView is supposed to be known

// Now loading the scaled image:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = ratio;

InputStream inputStream = (java.io.InputStream) new java.net.URL(url).getContent();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);

答案 2 :(得分:2)

你应该使用一种调整lazy initialization。我会一次使用3张图像,当前显示的图像和接下来的两张图像。这样,当用户正在查看image1时,image2和image3已经在内存中。当用户滑动到image2时,应将image4加载到上一个image1缓冲区(image3仍在内存中) 我希望这有帮助