简体   繁体   English

位图的GridView随机崩溃(内存不足异常)

[英]GridView of bitmaps randomly crashes (out of memory exception)

I'm getting random out-of-memory-exceptions when swiping or rotating a view that contains GridView of bitmaps. 滑动或旋转包含位图GridView的视图时,出现了随机的内存不足异常。

A BitmapHelpers class is being used to instantiate the images (obtained source from another SO post). 一个BitmapHelpers类用于实例化图像(从另一个SO帖子获取源)。

I'm not sure what the problem is, and I haven't yet run a memory profiler (I do have ADB installed on Desktop). 我不确定问题出在哪里,并且我还没有运行内存分析器(我确实在桌面上安装了ADB)。

I've tried commenting out the RecycleBitmap() call, and positioning it after SetImage() with no avail. 我尝试注释掉RecycleBitmap()调用,并将其放置在SetImage()之后无济于事。

Activity 活动

public class AttachmentsFragment : Activity
{
    //...

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle)
    {
        //...

        ImageViewGridAdapter attachmentGrid.Adapter = new ImageViewGridAdapter(Activity, Model.Attachments, _pictureWidth, _pictureHeight);

        //...
    }

    //...
}

GridView Adapter GridView适配器

public class ImageViewGridAdapter : ArrayAdapter<File>
{
    private readonly List<File> _imageFiles;

    public int PictureWidth { get; set; }
    public int PictureHeight { get; set; }

    public ImageViewGridAdapter(Context context, List<File> imageFiles, int w, int h) : base(context, 0, imageFiles)
    {
        _imageFiles = imageFiles;

        PictureWidth = w;
        PictureHeight = h;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        ImageView v = (ImageView) convertView;

        if (v == null)
        {
            LayoutInflater li = (LayoutInflater) this.Context.GetSystemService(Context.LayoutInflaterService);

            v = (ImageView) li.Inflate(Resource.Layout.GridItem_Image, null);           
        }

        File imageFile = _imageFiles[position];

        if (imageFile != null)
        {
            int width = PictureWidth;
            int height = PictureHeight;

            if( (new File(imageFile.Path)).Exists() )
            {
                using (Bitmap bitmap = imageFile.Path.LoadAndResizeBitmap(width, height))
                {
                    v.RecycleBitmap();
                    v.SetImageBitmap(bitmap);
                }
            }
        }

        return v;
    }
}

BitmapHelpers 位图助手

public static class BitmapHelpers
{
    /// <summary>
    /// This method will recyle the memory help by a bitmap in an ImageView
    /// </summary>
    /// <param name="imageView">Image view.</param>
    public static void RecycleBitmap(this ImageView imageView)
    {
        if (imageView == null) {
            return;
        }

        Drawable toRecycle = imageView.Drawable;
        if (toRecycle != null) {
            ((BitmapDrawable)toRecycle).Bitmap.Recycle ();
        }
    }

    /// <summary>
    /// Load the image from the device, and resize it to the specified dimensions.
    /// </summary>
    /// <returns>The and resize bitmap.</returns>
    /// <param name="fileName">File name.</param>
    /// <param name="width">Width.</param>
    /// <param name="height">Height.</param>
    public static Bitmap LoadAndResizeBitmap(this string fileName, int width, int height)
    {
        // First we get the the dimensions of the file on disk
        BitmapFactory.Options options = new BitmapFactory.Options
                                            {
                                                InPurgeable = true,
                                                InJustDecodeBounds = true
                                            };                      

        BitmapFactory.DecodeFile(fileName, options);

        // Next we calculate the ratio that we need to resize the image by
        // in order to fit the requested dimensions.
        int outHeight = options.OutHeight;
        int outWidth = options.OutWidth;
        int inSampleSize = 1;

        if (outHeight > height || outWidth > width)
        {
            inSampleSize = outWidth > outHeight
                               ? outHeight / height
                               : outWidth / width;
        }

        // Now we will load the image and have BitmapFactory resize it for us.
        options.InSampleSize = inSampleSize;
        options.InJustDecodeBounds = false;
        Bitmap resizedBitmap = BitmapFactory.DecodeFile(fileName, options);

        return resizedBitmap;
    }
}

Layout 布局

<?xml version="1.0" encoding="utf-8"?>
<fieldinspection.droid.views.LinearLayout2
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/ll_record_inspection"
  android:tag="panel_4"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:background="#FF200000">

<TabHost
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/ll_record_detail_tab"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:orientation="vertical"
      android:background="#FFAA8800">

      <TabWidget
        android:id="@android:id/tabs"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>

      <FrameLayout
        android:id="@android:id/tabcontent"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">

        <include layout="@layout/PagedFragmentRecordNoteBox_InspectionNotes"/>

        <include layout="@layout/RecordDetailsInspectionTabAttachments"/>

      </FrameLayout>

    </LinearLayout>

  </TabHost>

</fieldinspection.droid.views.LinearLayout2>

Tab Layout 标签布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/ll_record_inspections_attachments_tab"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@color/grey_solid">

  <fieldinspection.droid.views.custom.AttachmentButton
    android:id="@+id/btn_record_inspections_attachments_tab_button"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_margin="10dp"
    android:text="Add New Attachment"/>

  <GridView
    android:id="@+id/gv_record_inspections_attachments_tab_grid"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:numColumns="3"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="10dp"
    android:gravity="center"/>  

</LinearLayout>

Stacktrace 堆栈跟踪

05-09 17:06:05.240: E/dalvikvm-heap(2848): Out of memory on a 786448-byte allocation.
05-09 17:06:05.240: I/dalvikvm(2848): "main" prio=5 tid=1 RUNNABLE
05-09 17:06:05.240: I/dalvikvm(2848):   | group="main" sCount=0 dsCount=0 obj=0x40a4d460 self=0xae1828
05-09 17:06:05.240: I/dalvikvm(2848):   | sysTid=2848 nice=0 sched=0/0 cgrp=default handle=1074459784
05-09 17:06:05.240: I/dalvikvm(2848):   | schedstat=( 133234532000 27301683000 107351 ) utm=11520 stm=1803 core=1
05-09 17:06:05.240: I/dalvikvm(2848):   at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:299)
05-09 17:06:05.260: I/dalvikvm(2848):   at fieldinspection.droid.views.ImageViewGridAdapter.n_getView(Native Method)
05-09 17:06:05.260: I/dalvikvm(2848):   at fieldinspection.droid.views.ImageViewGridAdapter.getView(ImageViewGridAdapter.java:68)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.widget.AbsListView.obtainView(AbsListView.java:2033)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.widget.GridView.makeAndAddView(GridView.java:1323)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.widget.GridView.makeRow(GridView.java:328)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.widget.GridView.fillDown(GridView.java:281)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.widget.GridView.fillFromTop(GridView.java:403)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.widget.GridView.layoutChildren(GridView.java:1215)
05-09 17:06:05.260: I/dalvikvm(2848):   at android.widget.AbsListView.onLayout(AbsListView.java:1863)

com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    05-09 17:06:05.260: I/dalvikvm(2848):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    05-09 17:06:05.260: I/dalvikvm(2848):   at dalvik.system.NativeStart.main(Native Method)
    05-09 17:06:05.260: D/skia(2848): --- decoder->decode returned false
    05-09 17:06:05.270: I/MonoDroid(2848): UNHANDLED EXCEPTION: Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
    05-09 17:06:05.270: I/MonoDroid(2848): at Android.Runtime.JNIEnv.CallStaticObjectMethod (intptr,intptr,Android.Runtime.JValue[]) <0x00080>
    05-09 17:06:05.270: I/MonoDroid(2848): at Android.Graphics.BitmapFactory.DecodeFile (string,Android.Graphics.BitmapFactory/Options) <0x00167>
    05-09 17:06:05.270: I/MonoDroid(2848): at FieldInspection.Droid.Util.BitmapHelpers.LoadAndResizeBitmap (string,int,int) <0x00133>
    05-09 17:06:05.270: I/MonoDroid(2848): at FieldInspection.Droid.Views.ImageViewGridAdapter.GetView (int,Android.Views.View,Android.Views.ViewGroup) <0x001f3>
    05-09 17:06:05.270: I/MonoDroid(2848): at Android.Widget.ArrayAdapter.n_GetView_ILandroid_view_View_Landroid_view_ViewGroup_ (intptr,intptr,int,intptr,intptr) <0x00087>
    05-09 17:06:05.270: I/MonoDroid(2848): at (wrapper dynamic-method) object.1e84d773-bf58-463e-9e97-53e6c7fa57aa (intptr,intptr,int,intptr,intptr) <0x0005b>
    05-09 17:06:05.270: I/MonoDroid(2848):   --- End of managed exception stack trace ---
    05-09 17:06:05.270: I/MonoDroid(2848): java.lang.OutOfMemoryError
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:299)
    05-09 17:06:05.270: I/MonoDroid(2848):  at fieldinspection.droid.views.ImageViewGridAdapter.n_getView(Native Method)
    05-09 17:06:05.270: I/MonoDroid(2848):  at fieldinspection.droid.views.ImageViewGridAdapter.getView(ImageViewGridAdapter.java:68)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.AbsListView.obtainView(AbsListView.java:2033)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.GridView.makeAndAddView(GridView.java:1323)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.GridView.makeRow(GridView.java:328)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.GridView.fillDown(GridView.java:281)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.GridView.fillFromTop(GridView.java:403)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.GridView.layoutChildren(GridView.java:1215)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.AbsListView.onLayout(AbsListView.java:1863)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.View.layout(View.java:11283)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.ViewGroup.layout(ViewGroup.java:4224)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.View.layout(View.java:11283)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.ViewGroup.layout(ViewGroup.java:4224)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.View.layout(View.java:11283)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.ViewGroup.layout(ViewGroup.java:4224)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.View.layout(View.java:11283)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.ViewGroup.layout(ViewGroup.java:4224)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.View.layout(View.java:11283)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.view.ViewGroup.layout(ViewGroup.java:4224)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
    05-09 17:06:05.270: I/MonoDroid(2848):  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)

com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    05-09 17:06:05.280: I/dalvikvm(2848):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    05-09 17:06:05.280: I/dalvikvm(2848):   at dalvik.system.NativeStart.main(Native Method)
    05-09 17:06:05.280: E/dalvikvm(2848): VM aborting
    05-09 17:06:05.280: I/mono(2848): Stacktrace:
    05-09 17:06:05.280: I/mono(2848):   at Android.Runtime.JNIEnv.NewString (string) <0x0006b>
    05-09 17:06:05.280: I/mono(2848):   at Android.Util.Log.Info (string,string) <0x00073>
    05-09 17:06:05.280: I/mono(2848):   at Android.Runtime.AndroidEnvironment.UnhandledException (System.Exception) <0x00037>
    05-09 17:06:05.280: I/mono(2848):   at (wrapper dynamic-method) object.7587dfdd-5d38-472a-b7d4-2c05b2083bb2 (intptr,intptr,bool,int,int,int,int) <0x000cf>
    05-09 17:06:05.280: I/mono(2848):   at (wrapper native-to-managed) object.7587dfdd-5d38-472a-b7d4-2c05b2083bb2 (intptr,intptr,int,int,int,int,int) <0xffffffff>
    05-09 17:06:05.280: E/mono(2848): Unhandled Exception:
    05-09 17:06:05.280: E/mono(2848): System.NullReferenceException: Object reference not set to an instance of an object
    05-09 17:06:05.280: E/mono(2848): at Android.Runtime.JNIEnv.NewString (string) <0x0006b>
    05-09 17:06:05.280: E/mono(2848): at Android.Util.Log.Info (string,string) <0x00073>
    05-09 17:06:05.280: E/mono(2848): at Android.Runtime.AndroidEnvironment.UnhandledException (System.Exception) <0x00037>
    05-09 17:06:05.280: E/mono(2848): at (wrapper dynamic-method) object.7587dfdd-5d38-472a-b7d4-2c05b2083bb2 (intptr,intptr,bool,int,int,int,int) <0x000cf>
    05-09 17:06:05.280: E/mono(2848): at (wrapper native-to-managed) object.7587dfdd-5d38-472a-b7d4-2c05b2083bb2 (intptr,intptr,int,int,int,int,int) <0x0009b>
    05-09 17:06:05.280: I/mono(2848): [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
    05-09 17:06:05.280: I/mono(2848): at Android.Runtime.JNIEnv.NewString (string) <0x0006b>
    05-09 17:06:05.280: I/mono(2848): at Android.Util.Log.Info (string,string) <0x00073>
    05-09 17:06:05.280: I/mono(2848): at Android.Runtime.AndroidEnvironment.UnhandledException (System.Exception) <0x00037>
    05-09 17:06:05.280: I/mono(2848): at (wrapper dynamic-method) object.7587dfdd-5d38-472a-b7d4-2c05b2083bb2 (intptr,intptr,bool,int,int,int,int) <0x000cf>
    05-09 17:06:05.280: I/mono(2848): at (wrapper native-to-managed) object.7587dfdd-5d38-472a-b7d4-2c05b2083bb2 (intptr,intptr,int,int,int,int,int) <0x0009b>

I think it's b/c I'm instantiating a new bitmap for every call to GetView. 我想是b / c,我正在为每次调用GetView实例化一个新的位图。

I'm going to pre-instantiate the bitmaps and pass them to the adapter's constructor (instead of a list of file names). 我将预先实例化位图,并将其传递给适配器的构造函数(而不是文件名列表)。

if( (new File(imageFile.Path)).Exists() )
{
    using (Bitmap bitmap = imageFile.Path.LoadAndResizeBitmap(width, height))
    {
        //...
    }
 }

public override View GetView(int position, View convertView, ViewGroup parent)
{
    ImageView v = (ImageView) convertView;

    if (v == null)
    {
        LayoutInflater li = (LayoutInflater) this.Context.GetSystemService(Context.LayoutInflaterService);

        v = (ImageView) li.Inflate(Resource.Layout.GridItem_Image, null);           
    }

    File imageFile = _imageFiles[position];

    if (imageFile != null)
    {
        int width = PictureWidth;
        int height = PictureHeight;

        if( (new File(imageFile.Path)).Exists() )
        {
            using (Bitmap bitmap = imageFile.Path.LoadAndResizeBitmap(width, height))
            {
                v.RecycleBitmap();
                v.SetImageBitmap(bitmap);
            }
        }
    }

    return v;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM