Android 没有从内存中释放片段
我有一个活动,它包含一个具有适配器FragmentStatePagerAdapter的视图寻呼机。 每次输入活动时,它都会占用200 MB的内存,在退出活动(finish())并重新输入后,它会追加并加倍手机上使用的内存 在对问题进行故障排除之后,片段管理器似乎没有释放片段,尽管我试图删除它们,但它只是不起作用 我尝试清空正在添加的片段,以确保它不是片段内部的东西,问题仍然存在 我的适配器代码是Android 没有从内存中释放片段,android,android-fragments,android-viewpager,Android,Android Fragments,Android Viewpager,我有一个活动,它包含一个具有适配器FragmentStatePagerAdapter的视图寻呼机。 每次输入活动时,它都会占用200 MB的内存,在退出活动(finish())并重新输入后,它会追加并加倍手机上使用的内存 在对问题进行故障排除之后,片段管理器似乎没有释放片段,尽管我试图删除它们,但它只是不起作用 我尝试清空正在添加的片段,以确保它不是片段内部的东西,问题仍然存在 我的适配器代码是 private class ChildrenPagerAdapter extends Frag
private class ChildrenPagerAdapter extends FragmentStatePagerAdapter
{
private List<ChildBean> childrenBean;
public ChildrenPagerAdapter(FragmentManager fm, List<ChildBean> bean)
{
super(fm);
this.childrenBean = bean;
}
@Override
public int getItemPosition(Object object)
{
return PagerAdapter.POSITION_NONE;
}
@Override
public Fragment getItem(int position)
{
ReportFragment reportFragment = new ReportFragment();
reportFragment.childBean = childrenBean.get(position);
reportFragment.position = position;
reportFragment.mPager = mPager;
if(position == 0)
{
reportFragment.mostLeft = true;
}
if(position == childrenNumber - 1)
{
reportFragment.mostRight = true;
}
return reportFragment;
}
@Override
public int getCount()
{
return childrenNumber;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object)
{
// TODO Auto-generated method stub
super.destroyItem(container, position, object);
}
}
片段代码:
public class ReportFragment extends Fragment
{
public ChildBean childBean;
public int position;
public ImageView img;
public ImageLoader imageLoader;
public DisplayImageOptions options;
private int pee = 0;
private int poop = 0;
private double sleep = 0.0;
public ViewPager mPager;
public boolean mostLeft = false;
public boolean mostRight = false;
public ReportFragment()
{
}
@Override
public void onDestroyView()
{
super.onDestroyView();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.report_fragment, container, false);
if(mostLeft)
{
rootView.findViewById(id.btnleft).setVisibility(View.GONE);
}
if(mostRight)
{
rootView.findViewById(id.btnright).setVisibility(View.GONE);
}
rootView.findViewById(id.btnleft).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
});
rootView.findViewById(id.btnright).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
mPager.setCurrentItem(mPager.getCurrentItem() + 1);
}
});
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
Date dobchild = new Date();
((TextView) rootView.findViewById(id.tvday)).setText(sdf.format(dobchild));
ImageView childimg = (ImageView) rootView.findViewById(id.img_child);
((TextView) rootView.findViewById(id.tvchildname)).setText(childBean.childname);
((TextView) rootView.findViewById(id.tvclassname)).setText(((CustomApplication) getActivity().getApplication()).preferenceAccess.getCurrentClassName());
Date dob = null;
String age = "";
try
{
dob = sdf.parse(childBean.childdob);
age = GeneralUtils.getAge(dob.getTime(), getString(string.tv_day), getString(string.tv_month), getString(string.tv_year));
}
catch(ParseException e)
{
// TODO:
}
((CustomTextView) rootView.findViewById(id.tvchildage)).setText(age);
DisplayImageOptions options =
new DisplayImageOptions.Builder().showImageForEmptyUri(drawable.noimage).showImageOnFail(drawable.noimage).showStubImage(drawable.noimage).cacheInMemory()
.imageScaleType(ImageScaleType.NONE).build();
imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(childBean.childphoto, childimg, options);
final TextView tvpee = (TextView) rootView.findViewById(id.tvpeetime);
final TextView tvpoop = (TextView) rootView.findViewById(id.tvpootimes);
final TextView tvsleep = (TextView) rootView.findViewById(id.tvsleeptime);
rootView.findViewById(id.btnaddpee).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
pee = pee + 1;
if(pee > 9)
{
Toast.makeText(getActivity(), getString(string.tvareyousurepee), Toast.LENGTH_LONG).show();
}
tvpee.setText(String.format(getString(string.tvtimes), pee));
}
});
rootView.findViewById(id.btnminuspee).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if(pee > 0)
{
pee = pee - 1;
tvpee.setText(String.format(getString(string.tvtimes), pee));
}
}
});
rootView.findViewById(id.btnpluspoo).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
poop = poop + 1;
if(poop > 9)
{
Toast.makeText(getActivity(), getString(string.tvareyousurepoop), Toast.LENGTH_LONG).show();
}
tvpoop.setText(String.format(getString(string.tvtimes), poop));
}
});
rootView.findViewById(id.btnminuspoo).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if(poop > 0)
{
poop = poop - 1;
tvpoop.setText(String.format(getString(string.tvtimes), poop));
}
}
});
rootView.findViewById(id.btnaddsleep).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
sleep = sleep + 0.25;
tvsleep.setText(String.format(getString(string.tvhours), sleep));
}
});
rootView.findViewById(id.btnminussleep).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if(sleep > 0)
{
sleep = sleep - 0.25;
tvsleep.setText(String.format(getString(string.tvhours), sleep));
}
}
});
rootView.findViewById(id.btnsave).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Toast.makeText(getActivity(), "Report Saved.", Toast.LENGTH_LONG).show();
getActivity().finish();
}
});
return rootView;
}
}
请告知。。。谢谢您的代码似乎没有破坏视图,检查此项可能会解决此问题。ViewPager本身有一个方法
setOffscreenPageLimit
,允许您指定适配器保留的页数。所以你在远方的碎片将被摧毁
首先看一下您的代码,我没有看到您在片段onDestroy()中执行任何内存释放措施。片段本身被销毁和gc’ed的事实并不意味着您分配的所有资源也被删除
例如,我最关心的是:
imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(childBean.childphoto, childimg, options);
从这里我看到,似乎有一个ImageLoader的静态实例,每次出现新片段时都会被戳破,但我看不出一个即将死亡的片段会要求ImageLoader卸载它的内容。我觉得这很可疑
如果我是你,我会在活动重新启动后花费额外的200mb(如你所说)时转储应用程序的HPROF文件,并通过MAT(内存分析器工具)分析引用。很明显,您存在内存泄漏问题,我高度怀疑问题在于碎片本身没有被销毁
如果您不知道如何分析内存堆,这里有一个好方法。我无法计算它帮助我识别和消除应用程序内存泄漏的次数。不要在片段中存储对ViewPager或ImageView的“强”引用。您正在创建一个循环引用,它将所有内容都保存在内存中。相反,如果必须在活动之外保留对ViewPager或任何其他引用其上下文的元素的引用,请尝试使用WeakReference,例如:
private WeakReference<ViewPager> mPagerRef;
...
mPagerRef = new WeakReference<ViewPager>(mPager);
...
final ViewPager pager = mPagerRef.get();
if (pager != null) {
pager.setCurrentItem(...);
}
private WeakReference mPagerRef;
...
mPagerRef=新的WeakReference(mPager);
...
final ViewPager pager=mPagerRef.get();
如果(寻呼机!=null){
pager.setCurrentItem(…);
}
使用存储对活动或应用程序上下文引用的对象(提示:任何ViewGroup、ImageView、Activity等)遵循此模式应防止以“保留周期”的形式出现“内存泄漏”在eclipse中使用内存分析器工具后,我发现内存中存在的是片段的实际布局。 具体的相对布局 原因是我创建了一个CustomTextView,它将自定义字体设置为字体
Typeface face=Typeface.createFromAsset(context.getAssets(), "Helvetica_Neue.ttf");
this.setTypeface(face);
为了解决内存泄漏问题,我只做了以下发现的答案:
公共类FontCache{
私有静态哈希表fontCache=新哈希表();
公共静态字体get(字符串名称、上下文){
字体tf=fontCache.get(名称);
如果(tf==null){
试一试{
tf=Typeface.createFromAsset(context.getAssets(),name);
}
捕获(例外e){
返回null;
}
fontCache.put(名称,tf);
}
返回tf;
}
}
你能发布ReportFragment的代码吗?@Henrique完成,谢谢你的应用真的需要200mb吗FragmentStatePagerAdapter
用于提高效率,以在内存中保留最小数量的片段。然而,在你的应用程序中,使用mPager.setOffscreenPageLimit(6)有点违背这一点代码>基本上在内存中最多保留13个片段。@Luksprog是的,我达到了600 mb,并且活动即将结束,我将其放置在应用程序中,以便在应用程序中平滑滚动。。奇怪的是,事实上每次我滚动回我已经滚动过的片段时,它都会占用更多的内存。。。我在这上面花了20多个小时。。。而且没有运气。。感谢你的帮助。。。顺便说一句,我将把setoofscreenpagelimit设置为2。这是值得注意的。如果堆大小的最大值远小于600MB,你的应用程序怎么能使用600MB的RAM呢?你使用JNI吗?如果是这样的话,你必须在不需要的时候自己释放它的内存。另外,我认为您应该尝试一个只演示问题的全新项目,而不是向我们展示整个代码(因为大部分代码可能与问题无关)。试着用最少的代码来说明问题。你认为不令人接受的答案实际上给了你正确的方向(MAT)和信息是合适的吗?你能举个例子说明你更愿意这样做吗?对于每个片段中的每个视图?
Typeface face=Typeface.createFromAsset(context.getAssets(), "Helvetica_Neue.ttf");
this.setTypeface(face);
public class FontCache {
private static Hashtable<String, Typeface> fontCache = new Hashtable<String, Typeface>();
public static Typeface get(String name, Context context) {
Typeface tf = fontCache.get(name);
if(tf == null) {
try {
tf = Typeface.createFromAsset(context.getAssets(), name);
}
catch (Exception e) {
return null;
}
fontCache.put(name, tf);
}
return tf;
}
}