web-dev-qa-db-fra.com

Android ViewModel et démarrage

J'apprends ViewModel et LiveData et, dans le processus, il y a un doute.

Que dois-je faire si j'ai besoin de démarrer un Activity?

Est-il correct de transmettre le contexte sous forme de paramètre sur le ViewModel (le contexte ne sera pas stocké à l'intérieur de la fenêtre)?

ActivityAViewModel : ViewModel() {
    // ...

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

    // ...
}

ActivityA {
    // ...

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

    // ...
}

Sinon, quelle est la chose la plus correcte à faire dans ce cas?

10
Augusto Carmo

J'aime tirer des événements. :RÉ

Comme tout le monde dit ViewModel ne doit pas contenir Context ou référence aux classes contenant Context. Donc, ce n'est pas une bonne idée de faire startActivity de ViewModel.

Ce que je ferais, c'est avoir une liiveta contenant des données pour un événement. Cet événement sera tiré de votre viewModel basé sur votre logique commerciale (peut-être que vous montrez un compte à rebours et à la fin de celui-ci, vous passez à la prochaine activité?). C'est un LiveData et vous pouvez y observer. Sur la base des données de cet événement, vous pouvez commencer votre activité.

Vous voudrez peut-être regarder SingLeliveEvent

3
Arka Prava Basu

IMHO, ViewModel ne devrait rien savoir sur la vue et comment il présente des informations à l'utilisateur.

/**
 * 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;
    }
}
2
no_cola

ViewModels sont conçus pour maintenir et gérer un seul Activity données associées d'une manière consciente de cycle de vie

Vous ne devez pas enregistrer l'application contexte, activité ou afficher des objets dans ViewModel; parce que ViewModels sont conçus pour contenir des données associées à ces éléments (context, vues ...) afin de survivre à ces données pendant que des modifications de configuration telles que la rotation de l'écran (donc ViewModels ne sont pas conçues pour survivre les choses elles-mêmes (contexte, activité ou vues) mais les données qui leur sont associées.

Règle générale: Un seul ViewModel est conçu pour une seule activité et ses fragments associés. En tant que tel, il n'a aucun sens de démarrer une nouvelle activité à partir du ViewModel de l'activité mère.

Démarrer une nouvelle activité devrait provenir de l'activité actuelle, non de son ViewModel; L'activité des parents s'arrête en conséquence et, par conséquent, son ViewModel ne peut pas être consulté de la nouvelle activité.

S'il vous plaît vérifier this Discussion pour plus d'informations

0
Zain