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

时间:2014-05-14 17:46:52

标签: c# android xamarin.android

在滑动或旋转包含位图的GridView的视图时,我会得到随机的内存异常。

正在使用BitmapHelpers类来实例化图像(从另一个SO帖子中获取源)。

我不确定问题是什么,我还没有运行内存分析器(我在桌面上安装了ADB)。

我已经尝试注释掉RecycleBitmap()调用,并在SetImage()之后定位,但没有用。

活动

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适配器

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;
    }
}

布局

<?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>

标签布局

<?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>

堆栈跟踪

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>

1 个答案:

答案 0 :(得分:0)

我认为它是b / c我每次调用GetView都会实例化一个新的位图。

我要预先实例化位图并将它们传递给适配器的构造函数(而不是文件名列表)。

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;
}