【问题标题】:how to clean up FragmentPagerAdapter on destroy for memory leaks如何在销毁内存泄漏时清理 FragmentPagerAdapter
【发布时间】:2014-05-12 06:40:33
【问题描述】:

我有一个 FragmentPagerAdapter,它会导致内存不足错误和手机崩溃,因为它会泄漏内存,没有空间进行新的活动。平板电脑可以处理它工作正常但不能在手机上。我尝试了下面的代码,但它无法解决它。如何在销毁时清理 FragmentPagerAdapter?

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    try {
        FragmentManager manager = ((Fragment)object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment)object).commit();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


}

这是我的日志

05-12 06:35:32.130: E/AndroidRuntime(1493): FATAL EXCEPTION: main
05-12 06:35:32.130: E/AndroidRuntime(1493): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.company.project/com.company.project.ProjectMainActivity}: android.view.InflateException: Binary XML file line #156: Error inflating class <unknown>
05-12 06:35:32.130: E/AndroidRuntime(1493):     at     android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.os.Handler.dispatchMessage(Handler.java:99)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.os.Looper.loop(Looper.java:130)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.main(ActivityThread.java:3683)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Method.invokeNative(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Method.invoke(Method.java:507)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at dalvik.system.NativeStart.main(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493): Caused by: android.view.InflateException: Binary XML file line #156: Error inflating class <unknown>
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.createView(LayoutInflater.java:518)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.Activity.setContentView(Activity.java:1657)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.company.project.ProjectMainActivity.onCreate(ProjectMainActivity.java:57)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
05-12 06:35:32.130: E/AndroidRuntime(1493):     ... 11 more
05-12 06:35:32.130: E/AndroidRuntime(1493): Caused by: java.lang.reflect.InvocationTargetException
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Constructor.constructNative(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.createView(LayoutInflater.java:505)
05-12 06:35:32.130: E/AndroidRuntime(1493):     ... 24 more
05-12 06:35:32.130: E/AndroidRuntime(1493): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:460)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.Resources.loadDrawable(Resources.java:1709)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.Resources.getDrawable(Resources.java:581)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:162)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:787)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.Drawable.createFromXml(Drawable.java:728)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.Resources.loadDrawable(Resources.java:1694)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.widget.ImageView.<init>(ImageView.java:118)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.widget.ImageView.<init>(ImageView.java:108)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.company.project.widget.AspectRatioImageView.<init>(AspectRatioImageView.java:17)
05-12 06:35:32.130: E/AndroidRuntime(1493):     ... 27 more

我正在修改一个项目。在以前的版本中,它是通过查看寻呼机完成的 这已添加到适配器中。我很厚,我需要将其转换为 fragmentpageradapter。

 @Override
    public void destroyItem(View collection, int position, Object o) {
        View view = (View)o;
        ((ViewPager) collection).removeView(view);
        view = null;
    }

【问题讨论】:

    标签: android memory-leaks out-of-memory fragmentpageradapter


    【解决方案1】:

    OutOfMemoryError 并不一定意味着内存泄漏。

    您的堆栈跟踪显示

    java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    

    这意味着您正在尝试加载位图并且内存不足。

    你应该学习如何display bitmaps efficiently

    对于FragmentPagerAdapter,我们通常不会覆盖destroyItem()

    您的适配器应如下所示:

    public static class MyPagerAdapter extends FragmentPagerAdapter {
        private static final int COUNT = 5;
    
        public MyPagerAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }
    
        @Override
        public int getCount() {
            return COUNT;
        }
    
        @Override
        public Fragment getItem(int position) {
            switch (position) {
            case 0:
                return new FragmentA();
            case 1:
                return new FragmentB();
            case 2:
                return new FragmentC();
            case 3:
                return new FragmentD();
            case 4:
                return new FragmentE();    
            default:
                return null;
            }
        }
    
    }
    

    【讨论】:

    • 如果我直接从一开始就进入主要活动,它可以工作。但是如果我从使用我的 fragmentpageradapter 的介绍活动进入主要活动,它就会崩溃。我认为这意味着它会泄漏内存。
    • 你在片段中展示了什么?你有多少片段,viewpager 的屏幕外限制是多少?
    • 我有 5 个片段,其中一个通过 AsyncHttpClient 获取 json,而不是将其解析为 data.converts 为对象并显示在列表视图元素中。rest 仅显示它的布局并在单击按钮时进入主要活动。
    • 当您开始第二个活动时,第一个活动仍在使用部分可用内存。因此,您还应该确保您没有尝试在第二个活动中加载大型位图。
    • 问题不在于图像在磁盘上的大小。它与内存中的大小有关。它与尺寸(分辨率)有关。每个像素需要 32 位。因此,一个 1000x1000 像素的图像在磁盘上可能有 200KB 大小,但需要 4MB 内存。确保您有效地加载图像。
    【解决方案2】:

    FragmentStatePagerAdapter 可以作为一些与此解决方案相似的示例的解决方案。 FragmentStatePagerAdapter 仅显示 1 个片段并删除其他片段,因此堆大小保持在最小值。如果片段不像我的应用程序那样在它们之间交换数据,我建议使用 FragmentStatePagerAdapter。对我来说,情况并非如此。我需要保留一些片段。当我进入我的主要活动形式介绍活动时,所有片段都保持静止,但并非所有片段都是必要的。我的解决方案基于 fragmentstatepageradapter 解决方案。也许有更好的解决方案,但通过减少我保留在堆中的片段数量,我已经解决了粉碎问题。

    myPager.setOffscreenPageLimit(3);//previous was 5
    

    【讨论】:

      猜你喜欢
      • 2022-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 2021-07-13
      • 2014-06-18
      • 2016-05-31
      相关资源
      最近更新 更多