'outofmemoryerror' 在来自自定义 BaseAdapter 的 getView() 中
'outofmemoryerror' in the getView() from custom BaseAdapter
我有一个 Activity 的网格布局,用于显示 SD 文件夹中的图像。当我 select 一个文件夹时,所有图像都被添加到一个字符串列表中(当文件夹被更改时清理),并且图像构造在 getView() 方法中,使用列表中的这些字符串。
它正常工作了 5 或 6 次(显示了文件夹中的图像),但后来我更改了文件夹,我在自定义 BaseAdapter 的 getView() 中得到了一个 'outofmemoryerror'(参见代码行) , 但我不明白我的泄漏问题...
每张图片大小为 30-100 kB。
这是代码:
private ArrayList<String> itemList = new ArrayList<String>();
...
public void add(String path) {
itemList.add(path);
}
public void clean() {
itemList.clear();
}
public View getView(int position, View convertView, ViewGroup parent)
{
ImageView imageView;
if (convertView == null)
{
int iImageSize = mContext.getResources().getInteger(R.integer.grid_image_size);
int iImagePadding = mContext.getResources().getInteger(R.integer.grid_image_padding);
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(iImageSize, iImageSize));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(iImagePadding,iImagePadding,iImagePadding,iImagePadding);
}
else
imageView = (ImageView) convertView;
String sImagePath = itemList.get(position);
imageView.setTag(sImagePath);
imageView.setImageURI(Uri.parse(sImagePath)); // Crash HERE
return imageView;
}
跟踪日志:
04-21 10:10:50.697:E/art(1665):抛出 OutOfMemoryError "Failed to allocate a 1000012 byte allocation with 732188 free bytes and 715KB until OOM"
04-21 10:11:31.208: E/AndroidRuntime(1665): 致命异常: main
04-21 10:11:31.208: E/AndroidRuntime(1665): 过程: com.apps.apppictos, PID: 1665
04-21 10:11:31.208: E/AndroidRuntime(1665): java.lang.OutOfMemoryError: 无法分配 1000012 字节的分配,有 732188 个空闲字节和 715KB,直到 OOM
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 dalvik.system.VMRuntime.newNonMovableArray(本机方法)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.nativeDecodeStream(本机方法)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:635)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:611)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:391)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:417)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.drawable.Drawable.createFromPath(Drawable.java:1143)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.ImageView.resolveUri(ImageView.java:782)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.ImageView.setImageURI(ImageView.java:429)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 com.apps.apppictos.ImageAdapter.getView(ImageAdapter.java:93)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.AbsListView.obtainView(AbsListView.java:2347)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.makeAndAddView(GridView.java:1433)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.makeRow(GridView.java:361)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.fillDown(GridView.java:302)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.fillSpecific(GridView.java:582)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.layoutChildren(GridView.java:1287)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.AbsListView.onLayout(AbsListView.java:2151)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.onLayout(FrameLayout.java:514)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.onLayout(FrameLayout.java:514)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer.doCallbacks(Choreographer.java:580)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer.doFrame(Choreographer.java:550)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.os.Handler.handleCallback(Handler.java:739)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.os.Handler.dispatchMessage(Handler.java:95)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.os.Looper.loop(Looper.java:135)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.app.ActivityThread.main(ActivityThread.java:5257)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 java.lang.reflect.Method.invoke(本机方法)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 java.lang.reflect.Method.invoke(Method.java:372)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
04-21 10:11:31.208: E/AndroidRuntime(1665): 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
04-21 10:11:39.427: I/art(1665): 将目标 GC 堆从 49MB 钳制到 48MB
是的,使用图像可能会导致您的设备内存不足。分配的内存因设备而异。
两种方法:
使用 LruCache class 优化内存使用和缓存
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
使用 Picasso 强大的图像下载和缓存库 Android
当有人膨胀 CustomView 时也会发生这种情况:
inflate(getContext, R.layout.my_custom_view_layout, this)
而不是:
inflate(getContext, R.layout.my_custom_view_layout, null)
我有一个 Activity 的网格布局,用于显示 SD 文件夹中的图像。当我 select 一个文件夹时,所有图像都被添加到一个字符串列表中(当文件夹被更改时清理),并且图像构造在 getView() 方法中,使用列表中的这些字符串。
它正常工作了 5 或 6 次(显示了文件夹中的图像),但后来我更改了文件夹,我在自定义 BaseAdapter 的 getView() 中得到了一个 'outofmemoryerror'(参见代码行) , 但我不明白我的泄漏问题...
每张图片大小为 30-100 kB。
这是代码:
private ArrayList<String> itemList = new ArrayList<String>();
...
public void add(String path) {
itemList.add(path);
}
public void clean() {
itemList.clear();
}
public View getView(int position, View convertView, ViewGroup parent)
{
ImageView imageView;
if (convertView == null)
{
int iImageSize = mContext.getResources().getInteger(R.integer.grid_image_size);
int iImagePadding = mContext.getResources().getInteger(R.integer.grid_image_padding);
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(iImageSize, iImageSize));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(iImagePadding,iImagePadding,iImagePadding,iImagePadding);
}
else
imageView = (ImageView) convertView;
String sImagePath = itemList.get(position);
imageView.setTag(sImagePath);
imageView.setImageURI(Uri.parse(sImagePath)); // Crash HERE
return imageView;
}
跟踪日志:
04-21 10:10:50.697:E/art(1665):抛出 OutOfMemoryError "Failed to allocate a 1000012 byte allocation with 732188 free bytes and 715KB until OOM"
04-21 10:11:31.208: E/AndroidRuntime(1665): 致命异常: main 04-21 10:11:31.208: E/AndroidRuntime(1665): 过程: com.apps.apppictos, PID: 1665 04-21 10:11:31.208: E/AndroidRuntime(1665): java.lang.OutOfMemoryError: 无法分配 1000012 字节的分配,有 732188 个空闲字节和 715KB,直到 OOM 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 dalvik.system.VMRuntime.newNonMovableArray(本机方法) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.nativeDecodeStream(本机方法) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:635) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:611) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:391) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:417) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.graphics.drawable.Drawable.createFromPath(Drawable.java:1143) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.ImageView.resolveUri(ImageView.java:782) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.ImageView.setImageURI(ImageView.java:429) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 com.apps.apppictos.ImageAdapter.getView(ImageAdapter.java:93) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.AbsListView.obtainView(AbsListView.java:2347) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.makeAndAddView(GridView.java:1433) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.makeRow(GridView.java:361) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.fillDown(GridView.java:302) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.fillSpecific(GridView.java:582) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.GridView.layoutChildren(GridView.java:1287) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.AbsListView.onLayout(AbsListView.java:2151) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.onLayout(LinearLayout.java:1466) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.onLayout(FrameLayout.java:514) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.LinearLayout.onLayout(LinearLayout.java:1466) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.widget.FrameLayout.onLayout(FrameLayout.java:514) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.View.layout(View.java:15671) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewGroup.layout(ViewGroup.java:5038) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer.doCallbacks(Choreographer.java:580) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer.doFrame(Choreographer.java:550) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.os.Handler.handleCallback(Handler.java:739) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.os.Handler.dispatchMessage(Handler.java:95) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.os.Looper.loop(Looper.java:135) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 android.app.ActivityThread.main(ActivityThread.java:5257) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 java.lang.reflect.Method.invoke(本机方法) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 java.lang.reflect.Method.invoke(Method.java:372) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 04-21 10:11:31.208: E/AndroidRuntime(1665): 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 04-21 10:11:39.427: I/art(1665): 将目标 GC 堆从 49MB 钳制到 48MB
是的,使用图像可能会导致您的设备内存不足。分配的内存因设备而异。
两种方法:
使用 LruCache class 优化内存使用和缓存
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
使用 Picasso 强大的图像下载和缓存库 Android
当有人膨胀 CustomView 时也会发生这种情况:
inflate(getContext, R.layout.my_custom_view_layout, this)
而不是:
inflate(getContext, R.layout.my_custom_view_layout, null)