1

我正在使用一个简单的静态图片库,我在其中加载了至少 28 张图片,每张图片的大小都低于 150kb。

我在这里注意到两个问题:

1) 慢速滚动 2) 当我参加此活动两次 3 次时出现内存不足异常。

任何人指导我这里的问题是什么以及如何解决它?

任何帮助,将不胜感激

原木猫:

03-15 15:32:55.899: E/AndroidRuntime(14662): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:563)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:439)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.content.res.Resources.loadDrawable(Resources.java:1709)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.content.res.Resources.getDrawable(Resources.java:581)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.ImageView.resolveUri(ImageView.java:501)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.ImageView.setImageResource(ImageView.java:280)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.tackfu.Art$ImageAdapter.getView(Art.java:84)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.AbsListView.obtainView(AbsListView.java:1515)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.makeAndAddView(GridView.java:1269)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.makeRow(GridView.java:315)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.fillDown(GridView.java:268)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.fillGap(GridView.java:235)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4063)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.AbsListView.onTouchEvent(AbsListView.java:2471)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.View.dispatchTouchEvent(View.java:3885)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1750)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1135)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1734)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2216)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewRoot.handleMessage(ViewRoot.java:1887)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.os.Handler.dispatchMessage(Handler.java:99)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.os.Looper.loop(Looper.java:130)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.app.ActivityThread.main(ActivityThread.java:3687)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at java.lang.reflect.Method.invokeNative(Native Method)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at java.lang.reflect.Method.invoke(Method.java:507)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at dalvik.system.NativeStart.main(Native Method)

活动代码:

 @Override
        public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
            setContentView(R.layout.art);

 GridView gridview = (GridView) findViewById(R.id.gridv
 gridview.setAdapter(new ImageAdapter(this));

}

 public class ImageAdapter extends BaseAdapter {
            private Context mContext;

            public ImageAdapter(Context c) {
                mContext = c;
            }

            public int getCount() {
                return mThumbIds.length;
            }

            public Object getItem(int position) {
                return null;
            }

            public long getItemId(int position) {
                return 0;
            }

            // create a new ImageView for each item referenced by the Adapter
            public View getView(int position, View convertView, ViewGroup parent) {
                ImageView imageView;
                if (convertView == null) {  // if it's not recycled, initialize some attributes
                    imageView = new ImageView(mContext);
                    imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
                    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    imageView.setPadding(8, 8, 8, 8);
                } else {
                    imageView = (ImageView) convertView;
                }

                imageView.setImageResource(mThumbIds[position]);
                return imageView;
            }

            // references to our images
            private Integer[] mThumbIds = {
                    R.drawable.i1, R.drawable.i2,
                    R.drawable.i3, R.drawable.i4,
                    R.drawable.i5, R.drawable.i6,
                    R.drawable.i7, R.drawable.i8,
                    R.drawable.i9, R.drawable.i10,
                    R.drawable.i11, R.drawable.i12,
                    R.drawable.i13,R.drawable.i14,
                    R.drawable.i15,R.drawable.i16,
                    R.drawable.i17,R.drawable.i18,
                    R.drawable.i19,R.drawable.i20,
                    R.drawable.i21, R.drawable.i22,
                    R.drawable.i23, R.drawable.i24,
                    R.drawable.i26, R.drawable.i28,
                    R.drawable.i29, R.drawable.i30
            };
        }
4

3 回答 3

1

28 张 150KB 大小的图像大约是 ~4MB RAM。加上应用程序数据,它不适合小堆。您可以将大堆设置为 manifest

android:largeHeap="true"

但是这种方法看起来是一种解决方法,因为您有无限的内存并且图像数量的增加可能会再次导致此错误。您还应该使用延迟加载或根据设备屏幕大小调整图像大小。

于 2013-03-15T10:46:03.863 回答
1

不使用时回收位图。使用视图支架以获得更好的性能。 http://www.youtube.com/watch?v=wDBM6wVEO70。我建议你看看链接。无论适用于 listview 也适用于 gridview 和视频讨论它。该视频还对视图支架进行了讨论,这正是您应该使用的以避免内存泄漏。

在http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html也有关于避免内存泄漏的讨论。

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html。请参阅将按比例缩小的版本加载到内存中的部分

使用 MAT Analyzer 检查内存泄漏。http://www.youtube.com/watch?v=_CruQY55HOk

考虑http://developer.android.com/training/articles/perf-tips.html上的一些提示。

于 2013-03-15T10:49:54.017 回答
0

滚动慢的原因很简单。每次创建视图时,您都会在 UI 线程中加载图像。您应该将加载委托给另一个低优先级的线程。如果您愿意,您可以在 UI 线程中加载缩略图以快速显示某些内容,然后在后台加载全分辨率。

请记住,Android 有很多巧妙的技巧可以让您的应用程序变得更好,但您必须明智地使用它们。例如,Android 在所谓的绘图缓存中缓存静态视图,但在 ImgaeViews 的情况下,它是没有意义的,因为它需要额外的内存并且什么也没有。使用硬件加速 UI 会使用更多内存,因为每个视图缓存都是在二次幂纹理上绘制的。这意味着 100x35px 按钮将占用 128x64x4 字节的额外内存。Android 也会尝试使用某种抗锯齿,例如线性纹理采样器 - 这很好,但会占用大量 CPU 时间,您可能希望将其关闭。

通过 setImageResource 加载图像几乎没有控制权。您可能希望自己加载图像,以便更精确地控制加载和卸载。您还可以稍微缓存图像。LRU 缓存是用于此类用途的一个很好的示例:http: //developer.android.com/reference/android/util/LruCache.html。您可以加载当前图像并在左侧预加载一张,在右侧预加载一张。当用户返回上一个图像时,您会将其保存在内存中。

此外,如果您希望使用蛮力,您可以使用 NativeBuffer 缓存您的图像:http ://code.google.com/p/native-buffer/ 。它会迫使你重新设计你的画廊,但它可以加速大量图像应用程序。

于 2013-03-15T11:08:23.167 回答