MVVM:ViewModel逻辑需要来自数据库的信息,但是如何等待数据?

问题描述 投票:0回答:2

我是 MVVM 新手,正在尝试弄清楚如何组织我的应用程序。我制作了一个简化的登录应用程序来帮助解决问题。

我将应用程序分为几层:Activity -> ViewModel -> Repository -> Database。
我有几个 Activity,每个 Activity 都有其特定的 ViewModel(即 LoginActivity 访问 LoginViewModel)。有一个存储库用于通过 Dao 接口访问 Room 数据库。所有 ViewModel 都包含一个 LocalRepository 变量。

我知道活动应该只处理用户界面作业。因此,LoginActivity 通过 EditText 视图从用户那里获取用户名,显示成功和失败 Toast,启动下一个活动等。但要实际登录用户,需要调用 loginViewModel.login(username),以便 ViewModel 可以处理所有业务逻辑。

LoginViewModel 需要检查用户是否已存在于数据库中。但是ViewModel应该如何等待数据库结果呢?

  1. 观察 LiveData 在视图模型中不起作用(
    currentUser.observe(LoginActivity.this, new Observer<User>()
    LoginActivity.this
    返回错误:“'LoginActivity'不是封闭类”)。
  2. 创建回调似乎不太优雅。
  3. 添加 wait() 行简直是愚蠢的。
  4. 我可以将逻辑移至 LoginActivity,这将允许我等待用户从数据库返回。但我现在不是在UI层执行逻辑吗?
myViewModel.getUserByName(username).observe(this, new Observer<User>() {
            @Override
            public void onChanged(User userFromDatabase) {
                // If userFromDatabase is not null, login as this user
            }
        });

也许我遗漏了架构的结构。
或者有没有一种从 ViewModel 访问数据库的技术?
或者我读到关于添加另一个“模型”层?还是服务?
这么多的技术和选择,希望有人能解决问题。

干杯。这是代码:


登录活动:

public void loginButtonClicked(View v){
        // TODO: Stub. Login user
        String msg = myViewModel.loginUser(splashUserInput.getText().toString());
        if(msg.isEmpty()){
            Intent intent = new Intent(this, DEFAULT_FIRST_ACTIVITY);
            startActivity(intent);
        } else {
            Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        }
    }

LoginViewModel:newUser 返回 null,即使它确实存在于数据库中。

public String loginUser(String username) {
    if(username.isEmpty()) {
        // If empty user input
        return "Username field missing";
    } else if(currentUser.getValue() != null && username.equals(currentUser.getValue().getUsername())) {
        // If user is already logged on
        return null; // No errors
    } else {
        // Else if logging on to a different user
        User oldUser = currentUser.getValue();
        User newUser;


        newUser = localRepository.getUserByName(username).getValue();
        // newUser is null since the repository's background thread is still accessing the database.

        if(newUser == null) {
            return "Login Failed. Username does not exist.";
        } else {
            updateCurrentUser(oldUser, newUser);
            return null; // No errors
        }
    }
}

存储库:

public LiveData<User> getUserByName(String name) {
    return myDao.getUserByName(name);
}

我的道:

@Query("SELECT * FROM user_table WHERE username = :username")
LiveData<User> getUserByName(String username);



编辑 2022 年 4 月 22 日:以下是我尝试过的一些选项,但仍然没有解决方案:

在存储库中:

// getAllMarks returns LiveData<List<Mark>> from myDao
// Just grabbing the value returns null since the background thread is still grabbing the data
List<Mark> localMarks = repositoryLocal.getAllMarks.getValue(); // null


// So I tried to wait for the data, but I can't find the LifecycleOwner from within the repository.
// "this" should be the activity that called the viewModel that called the repository. (Required type: LifecycleOwner)
// Is it appropriate to just pass Activity down the line through viewModel to repository?
repositoryLocal.getAllMarks.observe(this, new Observer<List<Mark>>() {
        @Override
        public void onChanged(List<Mark> marks) {
                localMarks = marks;
        }
});



// getAllMarksValue returns List<Mark> from myDao
// IllegalStateException: will lock main thread
List<Mark> localMarks = repositoryLocal.getAllMarksValue(); 
java android database mvvm
2个回答
0
投票

您的用例不需要 LiveData,您只需从 Dao 返回 User 即可。喜欢, 我的道:

@Query("SELECT * FROM user_table WHERE username = :username")
User getUserByName(String username);

存储库:

public User getUserByName(String name) {
return myDao.getUserByName(name);
}

LiveData 仅应在底层数据频繁更改并且我们想要相应地进行一些更改时使用。


0
投票

当用户点击登录时,用户名和密码被发送到服务器,服务器响应用户信息以及令牌,始终使用您的应用程序存储库将服务器的响应存储到数据库中,服务器的响应是您的新用户,当您注销时,您需要清除数据库以存储新用户信息,如果您有所有用户的数据库表,您可以通过在您的数据库中添加另一列来获取登录用户名为“token”的数据库,因为只有登录的用户才能拥有令牌,所有其他用户都不能拥有令牌,然后在您的 DAO 中执行此操作

    @Query("SELECT * FROM users WHERE token IS NOT NULL ")
    User getLoggedInUser();

要获得新用户,您可以这样做

if(appDatabase.getLoggedInUser() != null){
        // do something
    }
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.