让我们举一个基本的例子
用于存储用户的表
@Entity (tableName="users")
class UsersEntity(
@PrimaryKey val id
var name:String,
...
)
用于存储角色的表
@Entity (tableName="roles")
class RolesEntity(
@PrimaryKey val id
var name:String,
...
)
用于存储用户和角色之间多对多关系的表
@Entity (tableName="roles")
class UserRoles(
@PrimaryKey val id
var userId:String,
var roleId:String
)
我在视图中需要的pojo类
class user(
var id:String,
var name:String,
.... other fields
var roles: List<Role>
)
在我的ViewModel
中,如何将user
也填满LiveData
来传递List<Role>
结果?
从一般的角度来看,我可以:
UserDao.getUserById(id)
,它从users表中返回LiveData
,还有RoleDao.getRolesForUserId(id)
,它返回LiveData
,其中包含用户的角色列表。然后在片段中,我可以做viewModel.getUserById().observe{}
和viewModel.getRolesForUserId().observe{}
。但这基本上意味着要有2位观察员,我非常有信心这不是要走的路。MediatorLiveData
答案 0 :(得分:3)
使用用户及其角色创建其他模型,并使用@Embedded
和@Relation
批注。
例如:
public class UserModel {
@Embedded
UserEntity user;
@Relation(parentColumn = "id", entityColumn = "userId", entity = UserRoles.class)
List<UserRoleModel> userRoles;
}
public class UserRoleModel {
@Embedded
UserRoles userRole;
@Relation(parentColumn = "roleId", entityColumn = "id")
List<RoleEntity> roles; // Only 1 item, but Room wants it to be a list.
}
您可以从此处使用UserModel
。
答案 1 :(得分:1)
在一个屏幕中可以有多个不同的数据流。
一方面,我们可以讨论在不更改用户本身的情况下更改用户角色列表,另一方面可以在不更新角色列表的情况下更改用户名。使用多个数据流的额外好处是,您可以在加载用户角色时显示用户数据。
我想,您可以使用用户和角色来避免同步问题。您可以像下面的示例中那样实现平稳的数据传递(从数据库到视图):
public class UserRolesViewModel extends ViewModel {
private final MutableLiveData<Integer> mSelectedUser;
private final LiveData<UsersEntity> mUserData;
private final LiveData<List<RolesEntity>> mRolesData;
private DataBase mDatabase;
public UserRolesViewModel() {
mSelectedUser = new MutableLiveData<>();
// create data flow for user and roles synchronized by mSelectedUser
mUserData = Transformations.switchMap(mSelectedUser, mDatabase.getUserDao()::getUser);
mRolesData = Transformations.switchMap(mSelectedUser, mDatabase.getRolesDao()::getUserRoles);
}
public void setDatabase(DataBase dataBase) {
mDatabase = dataBase;
}
@MainThread
public void setSelectedUser(Integer userId) {
if (mDatabase == null)
throw new IllegalStateException("You need setup database before select user");
mSelectedUser.setValue(userId);
}
public LiveData<UsersEntity> getUserData() {
return mUserData;
}
public LiveData<List<RolesEntity>> getRolesData() {
return mRolesData;
}
}
最好将数据源实现封装在Repository
类中,然后像this paragraph一样通过DI注入。
@Entity(tableName = "users")
public class UsersEntity {
@PrimaryKey
public int id;
public String name;
}
@Entity(tableName = "roles")
public class RolesEntity {
@PrimaryKey
public int id;
public String name;
}
这个实体需要特别注意,因为我们需要声明外键来使 joun 操作更有意义
@Entity(tableName = "user_roles", primaryKeys = {"user_id", "role_id"}, foreignKeys = {
@ForeignKey(entity = UsersEntity.class, parentColumns = "id", childColumns = "user_id"),
@ForeignKey(entity = RolesEntity.class, parentColumns = "id", childColumns = "role_id")
})
public class UserRolesEntity {
@ColumnInfo(name = "user_id")
public int userId;
@ColumnInfo(name = "role_id")
public int roleId;
}
@Dao
public interface UserDao {
@Query("SELECT * from users WHERE id = :userId")
LiveData<UsersEntity> getUser(int userId);
}
@Dao
public interface RolesDao {
@Query("SELECT * FROM roles INNER JOIN user_roles ON roles.id=user_roles.role_id WHERE user_roles.user_id = :userId")
LiveData<List<RolesEntity>> getUserRoles(int userId);
}
@Database(entities = {UsersEntity.class, RolesEntity.class, UserRolesEntity.class}, version = 1)
public abstract class DataBase extends RoomDatabase {
public abstract UserDao getUserDao();
public abstract RolesDao getRolesDao();
}