【问题标题】:ViewPager memory leakViewPager 内存泄漏
【发布时间】:2016-06-02 12:04:18
【问题描述】:

我有一个运行良好的 ViewPager,但其中存在内存泄漏。
我试图通过堆分析和 Eclipse 内存分析器找到泄漏。
事实证明,我得到了几个 ViewPager 实例,并且在多次活动后没有在堆中释放位图。
我的代码中的泄漏原因在哪里?

这是片段,我在其中使用 ViewPager 并在一段时间后滚动项目:

    private final int INTERVAL_TIME = 15000;
    private ViewPager mViewPager;
    private ViewPagerAdapter mAdapter;
    private Handler mHandler;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_bottom, container, false);
       ......

        mViewPager = (ViewPager) view.findViewById(R.id.pager);
        mAdapter = new ViewPagerAdapter(getActivity(), bottomItems);
        mViewPager.setAdapter(mAdapter);

        mHandler = new Handler();
        mHandler.postDelayed(UpdateTimeThread, INTERVAL_TIME);
        return view;
    }

    private Runnable UpdateTimeThread = new Runnable() {
        @Override
        public void run() {
            int position;
            if (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1) {
                position = 0;
            } else {
                position = mViewPager.getCurrentItem() + 1;
            }
            mViewPager.setCurrentItem(position, true);
            mHandler.postDelayed(this, INTERVAL_TIME);

        }
    };

这是我的 PagerAdapter,它可以在屏幕上同时显示 3 个项目(如果它们的 format.equals("1"))或一次显示 2 个项目,以防其中一个是双倍大小的(format.equals("2 "))

public class ViewPagerAdapter extends PagerAdapter {
private final List<JsonParsed.BottomItem> bottomItems;
private Activity activity;

public ViewPagerAdapter(Activity activity, List<JsonParsed.BottomItem> bottomItems) {
    this.activity = activity;
    this.bottomItems = bottomItems;
}

@Override
public int getCount() {
    if (bottomItems.size() < 3) {
        return 1;
    }
    return (int) Math.floor((float) bottomItems.size() / 3f);
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

@Override
public Object instantiateItem(ViewGroup container, final int position) {
    LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View itemView = inflater.inflate(R.layout.pager_item, container, false);
    ImageView pic = (ImageView) itemView.findViewById(R.id.image_item);
    ImageView pic2 = (ImageView) itemView.findViewById(R.id.image_item2);
    ImageView pic3 = (ImageView) itemView.findViewById(R.id.image_item3);
    pic.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            click(bottomItems.get(position * 3));
        }
    });
    pic2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            click(bottomItems.get(position * 3 + 1));
        }
    });

    pic3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            click(bottomItems.get(position * 3 + 2));
        }
    });
    if (bottomItems.get(position * 3) != null) {
        pic.setImageBitmap(BitmapFactory.decodeFile(bottomItems.get(position * 3).getPrev(activity).getAbsolutePath()));
        if (bottomItems.get(position * 3).format.equals("1")) {
            pic.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 2f));
        } else if (bottomItems.get(position * 3).format.equals("2")) {
            pic.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
        }
    } else {
        pic.setVisibility(View.GONE);
    }

    if (bottomItems.size() > position * 3 + 1 && bottomItems.get(position * 3 + 1) != null) {
        pic2.setImageBitmap(BitmapFactory.decodeFile(bottomItems.get(position * 3 + 1).getPrev(activity).getAbsolutePath()));
        if (bottomItems.get(position * 3 + 1).format.equals("1")) {
            pic2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 2f));
        } else if (bottomItems.get(position * 3 + 1).format.equals("2")) {
            pic2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
        }
    } else {
        pic2.setVisibility(View.GONE);
    }
    if (bottomItems.size() > position * 3 + 2 && bottomItems.get(position * 3 + 2) != null) {
        pic3.setImageBitmap(BitmapFactory.decodeFile(bottomItems.get(position * 3 + 2).getPrev(activity).getAbsolutePath()));
        if (bottomItems.get(position * 3 + 2).format.equals("1")) {
            pic3.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 2f));
        } else if (bottomItems.get(position * 3 + 2).format.equals("2")) {
            pic3.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
        }
    } else {
        pic3.setVisibility(View.GONE);
    }

    container.addView(itemView);

    return itemView;
}

private void click(JsonParsed.BottomItem bottomItem) {
    if (bottomItem.url != null && !bottomItem.url.isEmpty()) {
        ((MainActivity) activity).showWebView(bottomItem.url);
    } else if (bottomItem.video != null && !bottomItem.video.isEmpty()) {
        ((MainActivity) activity).onPlayMedia(bottomItem.getVideo(activity).getAbsolutePath(), bottomItem.id, false);
    }
}

@Override
public void destroyItem(ViewGroup container, int position, Object view) {
    container.removeView((LinearLayout) view);
}

非常感谢您的任何建议

编辑:
终于解决了泄漏。
正如 Egor 所指出的,主要泄漏是由 Handler 引起的,
因为它保留了对 ViewPager 实例的引用,因此不会对实例进行垃圾收集。
最后我只是使用了惰性解决方案 - WeakHandler(开源库)。
正如 Egors 的文章中所述,我想它也是如此,
但是使用它非常方便,因为您只是像往常一样使用它 Handler:
WeakHandler().postDelayed(....) 就是这样。
我还为位图使用了周引用,所有内存泄漏都消失了

【问题讨论】:

  • 嗨,Leo,只是一个困惑..您能确认上面的代码是您所做的解决方案或其产生错误的代码
  • 上面的代码是导致泄漏的初始sn-p
  • 能否指导我使用weakHandler 来查看寻呼机。我应该在侧postDelayed 方法中调用我的寻呼机适配器

标签: android memory-leaks android-viewpager


【解决方案1】:

Handler 很可能是导致内存泄漏的原因。有一个wonderful article详细描述了这个问题,建议你使用WeakReference来解决这个问题。

【讨论】:

  • 感谢您的回答,文章真的很棒。但是我有点困惑如何在我的 Fragment 中实现静态 Runnable,因为我必须访问 ViewPager 并在其中调用非静态 MyHandler
  • 您可以将其作为参数传递并保存在 WeakReference 中。
猜你喜欢
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2013-01-20
相关资源
最近更新 更多