猿问

如何将 StartActivityForResult 事件注册到 ViewModel?[MVVM]

我在使用 Java 中的 MVVM 实现 Google 登录时遇到问题。在这里,您将以正常方式看到来自 Google 的示例代码:


问题:


在你的活动中:


@Override

public void onCreate(Bundle savedInstanceState) {

    /* Here is the Issue:

     * Google Object is defined in View - Activity

     * I would like to have Google Object defined in my ViewModel

     */

    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail().build();

    mGoogleSignInClient = GoogleSignIn.getClient(this, gso);

}


// when Google Button CLicked

@Override

public void onClick(View v) { signIn(); }


private void signIn() {

    /* Here is the Issue:

     * I have to get this process done in View Model

     * so view will not reference any Google Object

     */

    Intent signInIntent = mGoogleSignInClient.getSignInIntent();

    startActivityForResult(signInIntent, RC_SIGN_IN);

}


@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);


    // Below will be processed in ViewModel

    GoogleSignInClient.getSignInIntent(...);

    if (requestCode == RC_SIGN_IN) {

        Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);

        handleSignInResult(task);

    }

}

问题: *见评论


所以我想出了下面的想法:


在活动中:


// when Google Button CLicked

@Override

public void onClick(View v) { viewModel.loginGoogle(); }


private void subscribeUi() {

    // register startActivityForResult Event to ViewModel and set this activity as receiver...

    // viewModel.startActivityForResultEvent.setEventReceiver(this Activity)

    // How to do this?

}


@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

    // send the result to View Model

    viewModel.onResultFromActivity(requestCode,resultCode,data);


    // escallate to super

    super.onActivityResult(requestCode, resultCode, data)

}



慕工程0101907
浏览 185回答 4
4回答

大话西游666

我认为您可以执行以下操作,它不持有全局引用,context因此不会泄漏&nbsp; public void loginGoogle(Context context){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(isSigningIn)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;context.startActivityForResult(getGoogleSignInIntent(), GOOGLE_SIGN_IN)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isSigningIn = true;&nbsp; &nbsp; }

临摹微笑

替换 startActivityForResult 的文档和函数似乎不鼓励这样做:注册请求以启动由给定合同指定的结果活动。这会在与此调用者关联的注册表中创建一个记录,管理请求代码,以及在后台与 Intent 的转换。这必须无条件调用,作为初始化路径的一部分,通常作为 Activity 或 Fragment 的字段初始化程序。如果此片段的宿主是 ActivityResultRegistryOwner,则将使用宿主的 ActivityResultRegistry。否则,这将使用片段的活动注册表。注意“This must be called unconditionally, as part of initialization path”。另请注意此 IlliegalStateException 消息:片段 [this] 在创建后尝试注册 ForActivityResult。片段必须在创建之前调用“registerForActivityResult()”(即初始化、“onAttach() 或 onCreate())”。所以我的建议是将契约和registerForActivityResult()你的 Activity 或 FragmentonCreate放在你的视图模型/域类中的函数中,无论你将对结果做什么,这基本上就是你已经在做的事情。

狐的传说

您可以使用 SingleLiveData 打开新屏幕。您创建具有所有必要参数的类来启动活动在 ViewModel 中,您使用需要的参数创建此类您在 ViewModel 中创建单个实时数据字段并从活动/片段中观察它你用 SingleLiveData 发送这个类创建类:public Enum Screen {   LOGIN}在视图模型中:...private SingleLiveData<Screen> onOpenScreen = new SingleLiveData<Screen>()public SingleLiveData<Screen> observeScreenOpen() {    return onOpenScreen}public void loginGoogle(){    onOpenScreen.value = Screen.LOGIN}...在活动/片段中viewModel.observeScreenOpen(this, new Observer<Screen> {screen->    if(screen == Screen.LOGIN) {        //start your activity here    }})

慕盖茨4494581

我要做的是在被调用的 ViewModel 中注册一个回调,Activity 可以对其做出反应。然后 ViewModel 可以拥有大部分业务逻辑,但不必引用 Activity 或 Context,Activity 可以处理启动 Intent 的 Activity 特定内容。例子:回调接口:interface OnSignInStartedListener {&nbsp; &nbsp; void onSignInStarted(GoogleSignInClient client);}视图模型:public class ViewModel {&nbsp; &nbsp; private final OnSignInStartedListener mListener;&nbsp; &nbsp; public ViewModel(OnSignInStartedListener listener) {&nbsp; &nbsp; &nbsp; &nbsp; mListener = listener;&nbsp; &nbsp; }&nbsp; &nbsp; public void viewModelOnCreate() {&nbsp; &nbsp; &nbsp; &nbsp; // This is what i want: Google object defined in View Model&nbsp; &nbsp; &nbsp; &nbsp; // but I dont know how to call startActivityForResult from here?&nbsp; &nbsp; &nbsp; &nbsp; GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail().build();&nbsp; &nbsp; &nbsp; &nbsp; mGoogleSignInClient = GoogleSignIn.getClient(getApplication(), gso);&nbsp; &nbsp; }&nbsp; &nbsp; public void loginGoogle() {&nbsp; &nbsp; &nbsp; &nbsp; // Invoke callback here to notify Activity&nbsp; &nbsp; &nbsp; &nbsp; mListener.onSignInStarted(mGoogleSignInClient);&nbsp; &nbsp; }}活动:protected void onCreate(Bundle savedInstanceState) {&nbsp; &nbsp; ...&nbsp; &nbsp; mViewModel = new ViewModel(new OnSignInStartedListener() {&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public void onSignInStarted(GoogleSignInClient client) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; startActivityForResult(client.getSignInIntent(), RC_SIGN_IN);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; });&nbsp; &nbsp; ...}@Overridepublic void onClick(View v) {&nbsp; &nbsp; // Invokes listener this activity created to start sign in flow&nbsp; &nbsp; viewModel.loginGoogle();}希望有帮助!
随时随地看视频慕课网APP

相关分类

Java
我要回答