Android MVVM. Знает ли жизненный цикл модели запах кода или правильную конструкцию?

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

Чтобы не выполнять код, когда он не нужен, код моей модели в настоящее время подписывается на изменения телефонной связи в onCreate() и снимает с учета в onDestroy() осуществляя LifecycleObserver

Для этого я создаю и связываю свою модель с viewModel внутри кода Activity.

Почему-то это неправильно.

В идеальном мире Activity будет частью уровня View (V в MVVM) и должна знать только о viewModel, но в приведенном выше случае осведомленность о жизненном цикле заставляет действие также узнать о Model.

Итак, является ли модель с учетом жизненного цикла правильной концепцией? Или я должен переосмыслить дизайн?

1 ответ

Решение

Мне очень нравится этот шаблон. Примером реализации прослушивания состояния в глобальном разделяемом объекте является

public class WifiState {
    private static WifiState instance;
    public static synchronized WifiState getInstance(Context context) {
        if (instance == null) instance = new WifiState(context.getApplicationContext());
        return instance;
    }

    private final Context context;
    private final WifiManager wm;
    private WifiState(Context context) {
        this.context = context;
        wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    }

    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
            wifiStateLiveData.setValue(state);
        }
    };

    public LiveData<Integer> wifiState() { return wifiStateLiveData; }

    private final MutableLiveData<Integer> wifiStateLiveData = new MutableLiveData<Integer>() {

        @Override
        protected void onActive() {
            setValue(wm.getWifiState()); // update immediately
            context.registerReceiver(receiver, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
        }
        @Override
        protected void onInactive() {
            context.unregisterReceiver(receiver);
        }

        @Override
        public void setValue(Integer value) { // debounce non-change
            Integer old = getValue();
            if (old == null && value != null || old != null && !old.equals(value)) {
                super.setValue(value);
            }
        }
    };
}

Это позволяет вам использовать один и тот же источник из нескольких мест одновременно, не тратя время на создание нескольких широковещательных приемников и т. Д.

public class SomeActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        WifiState.getInstance(this).wifiState().observe(this, state -> {
            if (state != WifiManager.WIFI_STATE_ENABLED) {
                Toast.makeText(this, "Please enable WIFI", Toast.LENGTH_LONG);
            }
        });
    }
}

Большим преимуществом использования возможностей жизненного цикла является то, что вам не нужно засорять свой код вызовами onStart / onStop, плюс вы больше не можете пропустить, например, вызовы onStop и утечки. Волшебство происходит в некоторой библиотеке, и ваш код может стать довольно простым и чистым. Реализуете ли вы LifecycleObserver или использовать LiveDataКогда все сделано правильно, вы получите более чистый код.

Позволяя платформе управлять временем жизни вашего ViewModel это тоже хорошо, но на самом деле она не сильно меняется с точки зрения схемы MV*, так как раньше у вас была ViewModel. Вы, вероятно, рассчитали свойства в Activity / Fragment напрямую. Что здесь нового, так это то, что каркас теперь сохраняет эту модель для вас в течение всего необходимого времени. Вы могли бы сделать это с сохраненным фрагментом раньше, и это именно то, что происходит сейчас под капотом.