我正在使用View Pager显示在我的应用程序中从网络下载的图像。图像的数量可以是5到20.我正在使用Volley库来进行网络操作。应用程序以前没有占用太多内存,但现在添加视图寻呼机后,应用程序需要大量内存,每次打开此活动时,堆中使用的内存会增加(从日志消息中检查)。我还使用Eclipse Memory分析器来检查泄漏的位置,这绝对是位图和此活动的多个实例。肯定存在泄漏,因为此活动未获得GC,一些参考文献正在阻止垃圾收集。我在这里添加了view viewr的实现。
public class ViewPagerAdapter extends PagerAdapter {
Context context;
public ViewPagerAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
return photoReferences.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == ((RelativeLayout) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
final ImageView im;
final ProgressBar pb;
View itemView = inflater.inflate(R.layout.place_photos_item, container, false);
im = (ImageView) itemView.findViewById(R.id.placeImage);
attributes = (TextView) itemView.findViewById(R.id.placeAttributes);
pb = (ProgressBar) itemView.findViewById(R.id.progressBarPhoto);
imageLoader.get(url, new ImageListener() {
public void onErrorResponse(VolleyError arg0) {
im.setImageResource(R.drawable.onErrorImage);
}
public void onResponse(ImageContainer response, boolean arg1) {
if (response.getBitmap() != null) {
im.startAnimation(AnimationUtils.loadAnimation(context, android.R.anim.fade_in));
im.setImageBitmap(response.getBitmap());
pb.setVisibility(View.GONE);
}
}
});
((ViewPager) container).addView(itemView);
return itemView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((RelativeLayout) object);
}
}
另外,我使用的是尺寸为screenBytes(screenWidth * screenHeight * 4)3倍的位图缓存。我正在测试Nexus 4运行4.3并且我从未遇到过OOM异常,因为此设备上的堆大小很大但是如果我打开活动,应用程序可能需要超过100 MB的内存(它会在大多数设备上崩溃)一次又一次,在此之前,无论怎样,它都需要大约16-20 mbs的内存。这是缓存代码。
public class BitmapCache extends LruCache<Object, Object> implements ImageCache {
public BitmapCache(int maxSize) {
super(maxSize);
}
@Override
public Bitmap getBitmap(String url) {
return (Bitmap) get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
有人可以建议我该怎么办才能发现泄漏? View Pager或我的Volley用法有什么问题吗?我对寻呼机的过渡感到不满意,有点滞后,那是相关的吗?
更新: Here's the screenshot of MAT, possible leak。这适用于使用Volley库的每个活动。我一直在阅读,但我无法解决问题。排球是否会导致泄漏,或者我做错了什么?
答案 0 :(得分:3)
您可以使用MAT找到您的泄漏。首先,您运行应用程序并泄漏一些活动实例。然后你抓住堆的快照并查找那些泄露的Activity对象......你可以使用'对象查询语言'(OQL)按类型查找它们(例如“SELECT * FROM com.foo.FooActivity”)。
找到泄漏的对象后,右键单击它并要求MAT将其所有传入的引用跟踪回GC根。泄露的参考文献将是其中之一。
为了更好地介绍该技术,您可以尝试这篇文章:
http://android-developers.blogspot.co.uk/2011/03/memory-analysis-for-android.html
答案 1 :(得分:2)
我猜你正在使用 Viewpager和Imageviews
关于图片视图您正在使用功能强大的图片下载和缓存库,例如最新的 Volley Imageloading(对大尺寸图片非常有用),可以高效地提高图片加载能力方式。
关于Viewpager 您必须使用高效的适配器 FragmentStatePagerAdapter : 当存在大量页面时,此版本的寻呼机更有用,更像列表视图。当页面对用户不可见时,它们的整个片段可能会被破坏,只保留该片段的保存状态。与FragmentPagerAdapter相比,这允许寻呼机保持与每个被访问页面相关联的更少内存,代价是在页面之间切换时可能产生更多开销。
请在使用FragmentPagerAdapter之前考虑一下因为它将整个片段存储在内存中,如果在ViewPager中使用了大量片段,可能会增加内存开销。与其兄弟相反,FragmentStatePagerAdapter仅存储片段的savedInstanceState,并在失去焦点时销毁所有片段。因此,当我们必须使用动态片段(如具有小部件的片段)时,应使用FragmentStatePagerAdapter,因为它们的数据可以存储在savedInstanceState中。即使存在大量碎片,它也不会影响性能。相反,当我们需要将整个片段存储在内存中时,应该使用它的兄弟FragmentPagerAdapter。当我说整个片段保存在内存中意味着,它的实例不会被破坏并且会产生内存开销。因此,建议仅在ViewPager的片段数较少时才使用FragmentPagerAdapter。如果片段是静态的,那将会更好,因为它们不会有大量的实例存储的对象。希望这能清除Android FragmentPagerAdapter和FragmentStatePagerAdapter之间的区别。
尝试学习Google android gallary应用示例,使用图片视图加载动画来提供出色的用户体验。
我希望这能解决你的堆积问题。
答案 2 :(得分:0)
您忘了回收已下载的Bitmaps
,因为它们不再需要。
基本上,每手动处理Bitmap
,您必须recyle()
。
话虽如此,您的destroyItem()
方法看起来应该是这样的:
public void destroyItem(ViewGroup container, int position, Object object) {
RelativeLayout rl = (RelativeLayout) object;
ImageView im = rl.findViewById(R.id.image_view);
bitmapDrawable = (BitmapDrawable) im.getDrawable();
if (bitmapDrawable != null && bitmapDrawable.getBitmap() != null) {
bitmap = bitmapDrawable.getBitmap();
bitmap.recycle();
}
container.removeView(rl);
}
答案 3 :(得分:0)
你应该查看新版本的Volley,旧版本确实导致了泄漏问题。
在旧版本中,Volley有4个线程做请求,并且每个都会保留一个请求,并请求保持强大的监听器引用,并且你的响应监听器用ImageView做一些事情,ImageView保留Activity的上下文。所以你的所有视图都泄露了。
在MAT中使用select * from instanceof android.app.Activity
,您将看到您的活动被泄露。
新版Volley解决了这个问题。 please check out here
使用它可以帮助您找到泄露的活动leakcanary