これは、匿名クラスを排除し、メモリリークのリスクを減らすための優れた手法(データホルダーを使用)ですか?

Is this a good technique (Using data holder) to eliminate anonymous class, to reduce memory leak risk


質問 written by Cheok Yan Cheng @2013-03-20 15:42:17Z

: 6 : 1 : 1

匿名クラスは、特にAndroidの世界で簡単にメモリリークを引き起こす可能性があります。Androidの世界では、設定の変更によりActivityまたはFragmentが突然破壊される可能性があります。 これは多くの例の1つです。

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またはFragmentで匿名クラスを作成すると、匿名クラスは常にActivityまたはFragmentへの暗黙的な参照を保持するためです。 そのため、設定の変更によりActivityが寿命を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));
    }
}
コメント 1

私はあなたのポイントを見ていますが、OnClickListenerは本当に外の世界に渡されるでしょうか?

written by ベニディ @2013-03-20 15:40:36Z

コメント 2

これはhttp://codereview.stackexchange.com適していると思います

written by ppeterka @2013-03-20 15:42:04Z

コメント 3

OnClickListenerまたはOnClickListenerのホルダー(行)がコード変更中に外部に公開されないようにすることができます。しかし、将来のメンテナーはそれらを偶然公開するかもしれません。誰も知らない。開発者としての私たちにとって最善は、そのようなリスクを減らすことです

written by -Cheok Yan Cheng @2013-03-20 15:44:38Z

回答 1 written by David Wasser @2013-03-20 16:03:47Z
5

このようなリファクタリングは役に立ちません。 HolderViewオブジェクトはActivityへの参照も保持するため、 Holderが外部に公開されている場合、メモリリークが発生します。 また、 MyOnClickLisnterインスタンスは、 staticとして宣言されていても、両方ともActivityへの参照を保持しているHolderLinearLayoutへの明示的な参照を保持しています。 私は匿名クラスのファンではありませんが、 ActivityまたはFragment外部で匿名のOnClickListenerが渡される可能性は非常に小さいと思います。 あなたが過度に妄想的であるように思えます。