0

以下是Fragment我用来显示简单秒表的精简版。该应用程序在平板电脑上运行良好。但是,在手机上,方向变化会导致在新活动中重新创建片段,我遇到了内存泄漏。

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;
            }

        }
    }
}

Eclipse MAT 甚至给了我这个:

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 回答