代码之家  ›  专栏  ›  技术社区  ›  N Sharma

如何在mvvm模式下登录成功时从viewmodel启动活动[重复]

  •  2
  • N Sharma  · 技术社区  · 8 年前

    嗨,我有一个活动 LoginActivity.kt LoginViewModel . 我正在调用 login LoginView模型 . 一旦成功,我想开始家庭活动。在MVVM方法中,正确的方法是什么?

    LoginView模型。千吨

    class LoginViewModel : BaseViewModel<LoginNavigator>(), AnkoLogger {
    
        val emailField = ObservableField<String>()
    
        private val email: String
            get() = emailField.get()
    
        val passwordField = ObservableField<String>()
    
        private val password: String
            get() = passwordField.get()
    
        val progressVisibility: ObservableInt = ObservableInt(View.GONE)
    
        @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
        fun login(view: View) {
          // here I am calling API and on success
        }
    
        /**
         * Validate email and password. It checks email and password is empty or not
         * and validate email address is correct or not
         * @param email email address for login
         * @param password password for login
         * @return true if email and password pass all conditions else false
         */
        private fun isEmailAndPasswordValid(email: String, password: String): Boolean {
    
            if (email.isEmpty()) return false
    
            if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) return false
    
            if (password.isEmpty()) return false
    
            return true
        }
    
    }
    

    class LoginActivity : BaseActivity(), LoginNavigator {
    
        @Inject
        lateinit var loginViewModel: LoginViewModel
    
        override fun onCreate(savedInstanceState: Bundle?) {
            performDependencyInjection()
            super.onCreate(savedInstanceState)
            val activityLoginBinding: ActivityLoginBinding = DataBindingUtil.setContentView<ActivityLoginBinding>(this, R.layout.activity_login)
            activityLoginBinding.loginViewModel = loginViewModel
            loginViewModel.mNavigator = this
        }
    
    1 回复  |  直到 8 年前
        1
  •  2
  •   Long Ranger    8 年前

    假设一个简单的场景使用您的登录想法,用户登录失败,应用程序需要制作一个简单的Toast或SnackBar来显示相关信息,例如“您的用户名和密码不正确”。你需要的代码是

    吐司(必填 Context )

    Toast.makeText(context, text, duration).show();
    

    View )

    Snackbar.make(findViewById(R.id.myCoordinatorLayout),
                                    R.string.email_archived, Snackbar.LENGTH_SHORT);
    

    如果您想在ViewModel中使用它(我不熟悉Kotlin)

      @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
        void function login(final View view) {
          // here I am calling API and on success
          repo.login(result -> {
               if(result.statusCode == 401)
               Toast.makeText(view.getContext(), "Login failed...", duration).show();
          });
        }
    

    您将以相反的方式找到活动的引用,这使得代码更加复杂,并且很难维护,因为每次您都需要获取活动的引用 在视图模型中执行与视图或活动(而不是活动)相关的操作的活动或上下文

    从 google sample ,你可以看到 doSearch() 函数在输入完成时调用。在获取搜索结果后,绑定将把最新的结果放回该观察者,现在是活动作业来更新适配器中的结果。

    private void initSearchInputListener() {
            binding.get().input.setOnEditorActionListener((v, actionId, event) -> {
                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                    doSearch(v);
                    return true;
                }
                return false;
            });
            binding.get().input.setOnKeyListener((v, keyCode, event) -> {
                if ((event.getAction() == KeyEvent.ACTION_DOWN)
                        && (keyCode == KeyEvent.KEYCODE_ENTER)) {
                    doSearch(v);
                    return true;
                }
                return false;
            });
        }
    
        private void doSearch(View v) {
            String query = binding.get().input.getText().toString();
            // Dismiss keyboard
            dismissKeyboard(v.getWindowToken());
            binding.get().setQuery(query);
            searchViewModel.setQuery(query);
        }
    
    private void initRecyclerView() {
    
            binding.get().repoList.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    LinearLayoutManager layoutManager = (LinearLayoutManager)
                            recyclerView.getLayoutManager();
                    int lastPosition = layoutManager
                            .findLastVisibleItemPosition();
                    if (lastPosition == adapter.get().getItemCount() - 1) {
                        searchViewModel.loadNextPage();
                    }
                }
            });
            searchViewModel.getResults().observe(this, result -> {
                binding.get().setSearchResource(result);
                binding.get().setResultCount((result == null || result.data == null)
                        ? 0 : result.data.size());
                adapter.get().replace(result == null ? null : result.data);
                binding.get().executePendingBindings();
            });
    
            searchViewModel.getLoadMoreStatus().observe(this, loadingMore -> {
                if (loadingMore == null) {
                    binding.get().setLoadingMore(false);
                } else {
                    binding.get().setLoadingMore(loadingMore.isRunning());
                    String error = loadingMore.getErrorMessageIfNotHandled();
                    if (error != null) {
                        Snackbar.make(binding.get().loadMoreBar, error, Snackbar.LENGTH_LONG).show();
                    }
                }
                binding.get().executePendingBindings();
            });
        }
    

    此外,根据伊曼纽尔的回答,你会看到他的论点

    WeakReference to a NavigationController,该控制器包含 活动这是处理上下文绑定的常用模式 在ViewModel中填充。

    我强烈拒绝这一点有几个原因。第一:这通常意味着 您必须保留对NavigationController的引用 修复了上下文泄漏,但根本无法解决架构问题。

    (在我看来)最好的方法是使用LiveData,它是生命周期 知道并能做所有想要的事情。

    推荐文章