Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak with Timer

I am using a timer that is canceled and restarted on a listener event. It all works fine except that the the timer thread leaks the whole outer class.

My timer implementation is as follows:

        if(timer != null) {
            timer.cancel();
            timer = null;
            timer = new Timer();
        }
        timer.schedule(new TimerTask() { // Thread leaks!!!!
            @Override
            public void run() {
              mCallback.onHeaderMoving(newToolbarTranslationY );
            }
        } , 150);

I used MAT Analyser to track down the problem and ended up there. I also commented out the line with the callback but the thread still leaks so it is defenetly the timer itself. However I don't really understand what is the problem with that code.

As far as I understand from my research the problem is that the anonymous inner class (new Timertask()) holds a reference to the outer class and therefore can leak the whole context. But I still don't understand why the timer and also the reference to the context is not garbage collected after the thread runs out (after 150 ms +).

Is the context in this case somehow still not released even after the thread finished?

And finally how do I solve this leak? I set the timer to null but that didn't solved my problem.

Edit

 private OnHeaderMovingCallBack mCallback;
 private Timer timer = new Timer();

 //... some other parameters


public ScrollingToolbarManager(View toolbar , View pagerStrip , AbsListView listView , OnHeaderMovingCallBack headerMovingCallBack){
    this.toolbar = toolbar;
    this.pagerStrip = pagerStrip;

    this.listView = listView;

    mCallback = headerMovingCallBack;

    changeStartValues();

}

public static interface OnHeaderMovingCallBack{
    public void onHeaderMoving(int translationY);
}

 public void moveHeader(){

      //... some calculations

    //timer implementation from above
 }

moveHeader() is called on a scroll event of a listview

like image 946
marcel12345689 Avatar asked Oct 13 '25 11:10

marcel12345689


1 Answers

If you think that the problem is that the anonymous inner class holds a reference to the outer class, then simply use a static named inner class - this will hold no reference. Put something like this inside your class:

static class MyTimerTask extends TimerTask {
    private OnHeaderMovingCallBack mCallback;
    int newToolbarTranslationY;

    public MyTimerTask(OnHeaderMovingCallBack mCallback, int newToolbarTranslationY) {
        this.mCallback = mCallback;
        this.newToolbarTranslationY = newToolbarTranslationY;
    }

    @Override
    public void run() {
        mCallback.onHeaderMoving(newToolbarTranslationY);
    }
}
like image 131
lbalazscs Avatar answered Oct 15 '25 01:10

lbalazscs