重新创建片段时,自定义处理程序中的内存泄漏

时间:2013-01-29 13:01:46

标签: android android-fragments android-memory

以下是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

但是,当我在平板电脑上运行时分析内存时(以下是单个活动),上述内容不会出现。

有关如何解决此问题的任何想法?如果我正确地理解了问题,我可能没有,我认为当手机上的方向发生变化时会有多个处理程序被创建。

如果我的问题很难理解,请给我一个提示,我会尝试更好地解释。

1 个答案:

答案 0 :(得分:2)

使用Handler时,您应始终遵循一条简单的规则。每次你写handler.postDelayed时,你也应该在某处写handler.removeCallbacks

在您的情况下,您使用handler.postDelayed(timer, 0)方法拨打onCreateView,因此onDestroyView是最合适的地方handler.removeCallbacks(timer)

相关问题