6

匿名类很容易导致内存泄漏,尤其是在 Android 世界中,Activity 或 Fragment 可能由于配置更改而突然销毁。这是众多示例之一。

http://chaosinmotion.com/blog/?p=696

http://blog.andresteingress.com/2011/10/12/anonymous-inner-classes-in-android/

https://blogs.oracle.com/olaf/entry/memory_leaks_made_easy

Activity原因是,在or中创建匿名类时Fragment,匿名类将始终包含对Activityor的隐式引用Fragment。因此,当Activity由于配置更改而趋于报废时,如果匿名类被外部世界公开和持有,则无法对其进行垃圾收集。

所以,我想知道,使用数据持有者技术是否是一种完全消除匿名类、降低内存泄漏风险的好方法?或者,我是否过度偏执?

使用匿名类

public class HomeMenuFragment {
    private Parcelable selectedInfo = null;
    private List<View> homeMenuRows = new ArrayList<View>();

    private void fun() {
        ...
        ...
        row.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // homeMenuRows is member variable
                for (View r : homeMenuRows) {
                    r.setSelected(false);
                }
                row.setSelected(true);
                // selectedInfo is member variable
                selectedInfo = watchlistInfo;
            }
        });
    }
}

使用数据持有者技术进行重构

public class HomeMenuFragment {
    private static class Holder {
        public Parcelable selectedInfo = null;
        public final List<View> homeMenuRows = new ArrayList<View>();        
    }
    private final Holder holder = new Holder();

    private static class MyOnClickLisnter implements OnClickListener {
        private final Holder holder;
        private final LinearLayout row;
        private final WatchlistInfo watchlistInfo;

        public MyOnClickLisnter(Holder holder, LinearLayout row, WatchlistInfo watchlistInfo) {
            this.holder = holder;
            this.row = row;
            this.watchlistInfo = watchlistInfo;
        }

        @Override
        public void onClick(View arg0) {
            for (View r : holder.homeMenuRows) {
                r.setSelected(false);
            }
            row.setSelected(true);
            holder.selectedInfo = watchlistInfo;
        }        
    }

    private void fun() {
        ...
        ...
        row.setOnClickListener(new MyOnClickLisnter(holder, row, watchlistInfo));
    }
}
4

1 回答 1

5

像这样的重构没有帮助。中的View对象Holder还包含对 的引用Activity,因此如果Holder暴露给外界,您就会发生内存泄漏。此外,您的MyOnClickLisnter实例,即使它已声明static,也持有对 theHolder和 a的显式引用LinearLayout,这两者都持有对 的引用Activity。我不是匿名类的粉丝,但我认为匿名OnClickListener通过Activityor之外的机会Fragment非常非常小。在我看来,你过于偏执了。

于 2013-03-20T16:03:47.857 回答