У меня есть класс для CustomView, который должен иметь внутренние классы, оба реализуют Runnable для выполнения задания в отдельном потоке.

public class ValueSelector extends LinearLayout{

.....

private class AutoIncrementer implements Runnable {

    @Override
    public void run() {
        if (plusButtonIsPressed) {
            incrementValue();
            mHandler.postDelayed(new AutoIncrementer(), REPEAT_INTERVAL_MS);
        } else {
            mHandler.removeCallbacks(this);
            Thread.currentThread().interrupt();
        }
    }
}

private class AutoDecrementer implements Runnable {
    @Override
    public void run() {
        if (minusButtonIsPressed) {
            decrementValue();
            mHandler.postDelayed(new AutoDecrementer(), REPEAT_INTERVAL_MS);
        } else {
            mHandler.removeCallbacks(this);
            Thread.currentThread().interrupt();
        }
    }
}
}

Как их правильно очистить? Уничтожаются ли они автоматически при уничтожении Activity, на котором размещены эти CustomView?

Ура

0
Andy Strife 25 Ноя 2016 в 23:16

2 ответа

Лучший ответ

Он не будет уничтожен, что приведет к утечке памяти, поскольку ваш поток будет иметь сильную ссылку на ваше представление и, следовательно, на вашу активность.

Сделайте внутренний класс статическим и сохраните слабую ссылку на переменные, которые вам нужны в методе run.

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

Вот как должен выглядеть ваш runnable

private static class AutoDecrementer implements Runnable {

    AutoDecrementer (ValueSelector valueSelector ){
       this.weakRef = new WeakReference<>(valueSelector);
    }      


    @Override
    public void run() {
         ValueSelector valueSelector =  (ValueSelector )weakRef.get();
         if(valueSelector == null){
            return ;
          }  

        if (valueSelector.minusButtonIsPressed) {
            valueSelector .decrementValue();
            valueSelector .mHandler.postDelayed(new AutoDecrementer(), REPEAT_INTERVAL_MS);
        } else {
            valueSelector.mHandler.removeCallbacks(this);
            Thread.currentThread().interrupt();
        }
    }
}

Я не проверял на наличие ошибок.

1
Nishant Verma 27 Ноя 2016 в 01:04

Нет, это вызовет ошибку, если действие будет уничтожено, пока событие таймера еще не завершено. Чтобы этого избежать, используйте WeakReference для некоторого объекта, уменьшая значение. Но, как правило, это плохая практика - смешивать UI и какие-то лигики, потому что это сложно тестировать. Рассмотрите возможность использования библиотеки rxJava, это будет выглядеть так:

 Subscriptioin s = Observable.just(100, TimeUnit.Milliseconds)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.computation())
.subscribe(t -> decrementValue());

В вашем методе onPause () отмените это действие,

if (s != null && !s.inUnsubscribed()) { 
s.unsubscribe(); 
s = null; 
}
1
Alex Shutov 25 Ноя 2016 в 20:23