Могу ли я наблюдать за ViewModel, если я уберу обратные ссылки? - PullRequest
0 голосов
/ 24 апреля 2018

Предлагаемый способ реализации ViewModel состоит в том, чтобы представить изменяющиеся данные с помощью LiveData объектов для действий, фрагментов и представлений.Бывают случаи, когда LiveData не является идеальным ответом или вообще не отвечает.

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

В документации сказано, что ViewModel не должно содержать ссылок на действия, фрагменты или представления.Единственный ответ на вопрос «почему», который я нашел, состоит в том, что это может вызвать утечки памяти.Тогда как насчет очистки ссылок, чтобы избежать утечек памяти?

Для представлений это сложность.Нет определенного момента, когда вид исчезает.Но действия и фрагменты имеют определенный жизненный цикл.Так что есть места, которые можно отменить в качестве наблюдателей.

Что вы думаете?Допустимо ли регистрировать действия в качестве наблюдателей на ViewModels, если вы всегда будете их отменять?Вы нашли достоверную информацию по этому вопросу?

Я назначил небольшую награду за лучший ответ.Это не потому, что я думаю, что это рекомендуемое решение (так как оно не работает с представлениями).Я просто хочу узнать и расширить свои возможности.

public class ExampleViewModel extends ViewModel {

    public interface OnEndListener {
        public void onEnd();
    }

    private List<OnEndListener> onEndListeners = new ArrayList<>();

    public void setOnEndListener(OnEndListener onEndListener) {
        onEndListeners.add(onEndListener);
    }

    public void removeOnEndListener(OnEndListener onEndListener) {
        onEndListeners.remove(onEndListener);
    }

    public void somethingHappens() {
        for (OnEndListener onEndListener: new ArrayList<OnEndListener>(onEndListeners) ) {
            onEndListener.onEnd();
        }
    }
}

public class ExampleActivity extends AppCompatActivity {

    ExampleViewModel exampleViewModel;
    ExampleViewModel.OnEndListener onEndListener;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        onEndListener = new ExampleViewModel.OnEndListener() {
            @Override
            public void onEnd() {
                finish();
            }
        };
        exampleViewModel = ViewModelProviders.of(this).get(ExampleViewModel.class);
        exampleViewModel.setOnEndListener(onEndListener);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        exampleViewModel.removeOnEndListener(onEndListener);
    }
}

1 Ответ

0 голосов
/ 03 мая 2018

Задавать вопрос: «Разрешено ли мне ...» - не очень полезный вопрос, ИМО.В документах ясно, что то, что вы предлагаете, не рекомендуется и почему.Тем не менее, я ожидаю, что ваш код, вероятно, будет работать так, как ожидалось, и поэтому «разрешен» (т.е. не предотвращен техническими ограничениями).

Один из возможных сценариев ошибок: InstanceA, равный ExampleActivity, запускается и запускаетсякакое-то длительное задание на ExampleViewModel.Затем, до завершения задачи, устройство поворачивается и InstanceA уничтожается из-за изменения конфигурации.Затем между моментом, когда InstanceA уничтожен и создан новый InstanceB, долгосрочная задача завершается, и ваша модель представления вызывает onEndListener.onEnd().За исключением: о нет!onEndListener равно null, поскольку оно было очищено при уничтожении InstanceA и еще не было установлено InstanceB: NullPointerException

ViewModel было разработано (частично) точно для обработки крайних случаев, таких как приведенный выше сценарий.Таким образом, вместо того, чтобы работать против предполагаемого использования ViewModel, почему бы просто не использовать инструменты, которые он предлагает вместе с LiveData, чтобы выполнить то же самое?(И с меньшим количеством кода, я мог бы добавить.)

public class ExampleActivity extends AppCompatActivity {

    ExampleViewModel exampleViewModel;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        exampleViewModel = ViewModelProviders.of(this).get(ExampleViewModel.class);
        exampleViewModel.getOnEndLive().observe(this, new Observer<Boolean>() {
            @Override
            public void onChanged(@Nullable Boolean onEnd) {
                if (onEnd != null && onEnd) {
                    finish();
                }
            }
        });

    }
}

public class ExampleViewModel extends ViewModel {

    private MutableLiveData<Boolean> onEndLive = new MutableLiveData<>();

    public MutableLiveData<Boolean> getOnEndLive() {
        return onEndLive;
    }

    public void somethingHappens() {
        onEndLive.setValue(true);
    }
}

Думайте о LiveData в этом случае не как о фактических «данных» как таковых, а как о сигнале, который вы можете передать из вашей ViewModel в свою активность,Я использую этот шаблон все время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...