0

以下は、Fragment単純なストップウォッチを表示するために使用しているIの簡略版です。アプリはタブレット上で完全に機能しています。ただし、向きを変更するとフラグメントが新しいアクティビティで再作成される電話では、メモリリークが発生します。

public class TimerFragment extends BaseFragment {

    private static final int MESSAGE_UPDATE_TEXT = 0;

    private TextView text;

    private static final String KEY_START_TIME = "KEY_START_TIME";
    private static final String KEY_ELAPSED_TIME = "KEY_ELAPSED";

    private long startTime;
    private long elapsedTime;

    private static boolean running;

    private final TimerHandler handler = new TimerHandler(this);

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {     
        setHasOptionsMenu(true);
        setUpHomeButton(false);

        View view = inflater.inflate(R.layout.fragment_timer, container, false);

        text = (TextView) view.findViewById(R.id.timerText);

        if(savedInstanceState != null) {
            startTime = savedInstanceState.getLong(KEY_START_TIME);
            elapsedTime = savedInstanceState.getLong(KEY_ELAPSED_TIME);
        }

        if(running) {
            handler.removeCallbacks(timer);
            handler.postDelayed(timer, 0);
        }

        updateText();

        return view;
    }

    private void updateText() {
        if(elapsedTime == 0L) {
            text.setText("0:00");
            return;
        }

        int sec = (int) (elapsedTime / 1000);
        int min = sec / 60;
        sec = sec % 60;

        text.setText(min + ":" + sec);

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        handler.removeCallbacks(timer);

        outState.putLong(KEY_START_TIME, startTime);
        outState.putLong(KEY_ELAPSED_TIME, elapsedTime);
    }

    private final Runnable timer = new Runnable() {

        @Override
        public void run() {
            long now = System.currentTimeMillis();
            elapsedTime = now - startTime;

            running = true;
            handler.postDelayed(this, 1000);
            handler.sendEmptyMessage(MESSAGE_UPDATE_TEXT);
        }
    };

    private static class TimerHandler extends Handler {
        private final WeakReference<TimerFragment> weakFragment;

        public TimerHandler(TimerFragment f) {
            weakFragment = new WeakReference<TimerFragment>(f);
        }

        @Override
        public void handleMessage(Message msg) {
            TimerFragment fragment = weakFragment.get();
            switch (msg.what) {
            case MESSAGE_UPDATE_TEXT:
                if(fragment != null) {
                    fragment.updateText();
                }
                break;

            default:
                break;
            }

        }
    }
}

EclipseMATは私にこれさえ与えます:

One instance of "android.os.MessageQueue" loaded by "<system class loader>" occupies 1     529 600 (14,19%) bytes. The memory is accumulated in one instance of "android.os.Message"     loaded by "<system class loader>".

Keywords
android.os.Message
android.os.MessageQueue

ただし、タブレットで実行しているときにメモリを分析すると、上記は表示されません(常に単一のアクティビティ)。

これを修正する方法についてのアイデアはありますか?問題を正しく理解していれば、理解できないかもしれませんが、電話で向きの変更が発生すると、複数のハンドラーが作成されると思います。

私の問題が理解しにくい場合は、ヒントを教えてください。もっとよく説明しようと思います。

4

1 に答える 1

2

を使用するときは常に従う必要のある簡単なルールがありますHandler。あなたが書くたびにあなたはまたどこかhandler.postDelayedに書くべきです。handler.removeCallbacks

あなたの場合、あなたはメソッドを呼び出しhandler.postDelayed(timer, 0)onCreateViewいるので、呼び出すのにonDestroyView最も適切な場所ですhandler.removeCallbacks(timer)

于 2013-01-29T13:40:26.060 に答える