Android ViewModel и запуск активности - PullRequest
0 голосов
/ 21 февраля 2019

Я учу ViewModel и LiveData, и в процессе возникло сомнение.

Что мне делать, если мне нужно запустить Activity?

Можно ли передать контекст в качестве параметра в ViewModel (контекст не будет храниться внутри ViewModel)?

ActivityAViewModel : ViewModel() {
    // ...

    fun openActivityB(context: Context) {
        context.startActivity(...)
    }

    // ...
}

ActivityA {
    // ...

    fun onSomethingHappened() {
        viewModel.openActivityB(this)
    }

    // ...
}

Если нет, то, что наиболее правильно сделать в этом случае?

Ответы [ 6 ]

0 голосов
/ 25 февраля 2019

Мне нравятся события стрельбы.: D

Как все говорят, ViewModel не должно содержать Context или ссылку на классы, содержащие Context.Поэтому не рекомендуется делать startActivity из ViewModel.

. Я бы хотел получить LiveData, содержащий данные для события.Это событие будет запущено из вашей ViewModel на основе вашей бизнес-логики (может быть, вы показываете CountDown и в конце его переходите к следующему действию?).Это LiveData, и вы можете наблюдать за ним.На основании данных этого события вы можете начать свою деятельность.

Возможно, вы захотите посмотреть SingleLiveEvent

0 голосов
/ 22 февраля 2019

Было бы хорошим выбором дизайна, если модель представления ничего не знает о действиях.В основном, модели представления и действия играют наблюдаемую роль и роль наблюдателей.ViewModel, являясь оболочкой вашего хранилища, бизнес-модели или уровня оркестровки, обеспечивает потоковую передачу данных в реактивном стиле и играет заметную роль.Это означает, что несколько действий или фрагментов, являющихся наблюдателями, могут прослушивать одну модель представления.

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

Если у вас есть модифицированные или ohttp или другие библиотеки, которым нужен контекст, передайте им контекст через библиотеки dagger2 или Koin DI.Это была бы чистая архитектура.

0 голосов
/ 22 февраля 2019

ИМХО, viewmodel не должна ничего знать о представлении и о том, как оно предоставляет информацию пользователю.

/**
 * Activity (as view) responsible only for gathering actions and intentions from user and
 * show result state.
 * View must know "What user want". View knows meaning its interface.
 * Click on button 'login' means INTENTION to login somewhere.
 * This intention pass to ViewModel to process it and wait some changing state from LiveData.
 * For example implemented as Actions.
 */
public class LoginActivity extends AppCompatActivity {
    private LoginViewModel mLoginViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLoginViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
        mLoginViewModel.getAction().observe(this, new Observer<Action>() {
            @Override
            public void onChanged(@Nullable final Action action) {
                if(action != null){
                    handleAction(action);
                }
            }
        });

        //Emulate user intention
        mLoginViewModel.userWantToLogin("0123456789", "admin");
    }

    private void handleAction(@NonNull final Action action) {
        switch (action.getValue()){
            case Action.SHOW_WELCOME:
                //show Activity. 
                break;
            case Action.SHOW_INVALID_PASSWARD_OR_LOGIN:
                //show Toast
                break;
        }
    }
}

    public class LoginViewModel extends ViewModel {
        //Stores actions for view.
        private MutableLiveData<Action> mAction = new MutableLiveData<>();

        public LiveData<Action> getAction() {
            return mAction;
        }

        /**
         * Takes intention to login from user and process it.
         *
         * @param password Dummy password.
         * @param login Dummy login.
         */
        public void userWantToLogin(String password, String login){
            if(validateInfo(password, login)){
                showWelcomeScreen();
            }else {
                showPasswordOrLoginInvalid();
            }
        }

        /*
         * Changes LiveData. Does not act directly with view.
         * View can implement any way to show info
          * to user (show new activity, alert or toast)
         */
        private void showPasswordOrLoginInvalid() {
            mAction.setValue(new Action(Action.SHOW_INVALID_PASSWARD_OR_LOGIN));
        }

        /*
         * Changes LiveData. Does not act directly with view.
         * View can implement any way to show info
         * to user (show new activity, alert or toast)
         */
        private void showWelcomeScreen() {
            mAction.setValue(new Action(Action.SHOW_WELCOME));
        }

        //As example of some logic.
        private boolean validateInfo(String password, String login) {
            return password.equals("0123456789") && login.equals("admin");
        }
    }

public class Action {
    public static final int SHOW_WELCOME = 0;
    public static final int SHOW_INVALID_PASSWARD_OR_LOGIN = 1;
    private final int mAction;

    public Action(int action) {
        mAction = action;
    }

    public int getValue() {
        return mAction;
    }
}
0 голосов
/ 22 февраля 2019

ViewModels предназначены для хранения и управления отдельных Activity данных, связанных с жизненным циклом

Вы не должны сохранять контекст, активность или вид приложенияобъекты в ViewModel;потому что ViewModels предназначены для хранения данных, связанных с этими вещами (контекст, представления ...), чтобы выжить эти данные, в то время как изменения конфигурации, такие как поворот экрана (поэтому ViewModels не предназначены для выживания самих вещей (контекст,действия или представления), но данные, связанные с ними.

Общее правило: Одиночное ViewModel предназначено для отдельного действия и связанных с ним фрагментов. Поэтому не имеет смысла начинать новое действие сViewModel родительского действия.

Начало нового действия должно начинаться с текущего действия, а не с его ViewModel, родительское действие будет соответственно остановлено, и, следовательно, к его ViewModel нельзя получить доступ изновое занятие.

Пожалуйста, проверьте это обсуждение для получения дополнительной информации

0 голосов
/ 21 февраля 2019

Вы можете использовать Application контекст, который предоставляется AndroidViewModel, вы должны расширить AndroidViewModel, который является просто ViewModel, который включает Application ссылку.

0 голосов
/ 21 февраля 2019

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

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