2015-02-23 3 views
3

Я использую таймер, который отменяется и перезапускается на событии слушателя. Все работает отлично, за исключением того, что поток таймера утечки всего внешнего класса.Утечка памяти с таймером

Моя реализация таймера выглядит следующим образом:

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

Я использовал MAT Analyzer, чтобы отследить проблему и в конечном итоге там. Я также прокомментировал строку с обратным вызовом, но поток все еще течет, поэтому он сам по себе отключается. Однако я не совсем понимаю, в чем проблема с этим кодом.

Насколько я понимаю из моего исследования, проблема заключается в том, что анонимный внутренний класс (новый Timertask()) содержит ссылку на внешний класс и, следовательно, может просачивать весь контекст. Но я до сих пор не понимаю, почему таймер, а также ссылка на контекст - это не сбор мусора после завершения потока (после 150 мс +).

Является ли контекст в этом случае каким-то образом еще не выпущен даже после завершения потока?

И наконец, как решить эту утечку? Я установил таймер равным нулю, но это не решило мою проблему.

Редактировать

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() вызываются по событию прокрутки ListView

+0

Как и где определяется 'таймер'? – m0skit0

+0

Таймер; просто в заголовке класса. Это ты имел в виду? – marcel12345689

+0

Да, но укажите точный код в своем вопросе, включая все модификаторы. Нет такой вещи, как * заголовок класса *. – m0skit0

ответ

3

Если вы считаете, что проблема заключается в том, что анонимный внутренний класс содержит ссылку на внешний класс, то просто используйте статический внутренний класс - это не будет содержать ссылки. Поместите что-то подобное внутри вашего класса:

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); 
    } 
} 
Смежные вопросы