为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕工程0101907 2023-06-08 20:03:20
我在使用 Java 中的 MVVM 实现 Google 登录时遇到问题。在这里,您将以正常方式看到来自 Google 的示例代码:问题:在你的活动中:@Overridepublic 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@Overridepublic 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);}@Overridepublic 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@Overridepublic 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?}@Overridepublic 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)}
查看完整描述

4 回答

?
大话西游666

TA贡献1817条经验 获得超14个赞

我认为您可以执行以下操作,它不持有全局引用,context因此不会泄漏


  public void loginGoogle(Context context){


         if(isSigningIn)

            return


         context.startActivityForResult(getGoogleSignInIntent(), GOOGLE_SIGN_IN)

         isSigningIn = true;

    }


查看完整回答
反对 回复 2023-06-08
?
临摹微笑

TA贡献1982条经验 获得超2个赞

替换 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放在你的视图模型/域类中的函数中,无论你将对结果做什么,这基本上就是你已经在做的事情。


查看完整回答
反对 回复 2023-06-08
?
狐的传说

TA贡献1804条经验 获得超3个赞

您可以使用 SingleLiveData 打开新屏幕。

  1. 您创建具有所有必要参数的类来启动活动

  2. 在 ViewModel 中,您使用需要的参数创建此类

  3. 您在 ViewModel 中创建单个实时数据字段并从活动/片段中观察它

  4. 你用 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

    }

})


查看完整回答
反对 回复 2023-06-08
?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

我要做的是在被调用的 ViewModel 中注册一个回调,Activity 可以对其做出反应。然后 ViewModel 可以拥有大部分业务逻辑,但不必引用 Activity 或 Context,Activity 可以处理启动 Intent 的 Activity 特定内容。


例子:


回调接口:


interface OnSignInStartedListener {

    void onSignInStarted(GoogleSignInClient client);

}

视图模型:


public class ViewModel {

    private final OnSignInStartedListener mListener;


    public ViewModel(OnSignInStartedListener listener) {

        mListener = listener;

    }


    public void viewModelOnCreate() {

        // This is what i want: Google object defined in View Model

        // but I dont know how to call startActivityForResult from here?

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

        mGoogleSignInClient = GoogleSignIn.getClient(getApplication(), gso);

    }


    public void loginGoogle() {

        // Invoke callback here to notify Activity

        mListener.onSignInStarted(mGoogleSignInClient);

    }

}

活动:


protected void onCreate(Bundle savedInstanceState) {

    ...

    mViewModel = new ViewModel(new OnSignInStartedListener() {

        @Override

        public void onSignInStarted(GoogleSignInClient client) {

            startActivityForResult(client.getSignInIntent(), RC_SIGN_IN);

        }

    });

    ...

}


@Override

public void onClick(View v) {

    // Invokes listener this activity created to start sign in flow

    viewModel.loginGoogle();

}

希望有帮助!


查看完整回答
反对 回复 2023-06-08
  • 4 回答
  • 0 关注
  • 184 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信