Ali*_*lin 10 android-room android-livedata android-viewmodel android-architecture-components android-jetpack
我们来看一个基本的例子
用于存储用户的表
@Entity (tableName="users")
class UsersEntity(
@PrimaryKey val id
var name:String,
...
)
Run Code Online (Sandbox Code Playgroud)
用于存储角色的表
@Entity (tableName="roles")
class RolesEntity(
@PrimaryKey val id
var name:String,
...
)
Run Code Online (Sandbox Code Playgroud)
用于存储用户和角色之间的多对多关系的表
@Entity (tableName="roles")
class UserRoles(
@PrimaryKey val id
var userId:String,
var roleId:String
)
Run Code Online (Sandbox Code Playgroud)
我在视图中需要的pojo类
class user(
var id:String,
var name:String,
.... other fields
var roles: List<Role>
)
Run Code Online (Sandbox Code Playgroud)
在我,我ViewModel怎么能把user结果传递给LiveData已经List<Role>填满?
从一般方面来看,我可以:
UserDao.getUserById(id)返回LiveData从用户表,并RoleDao.getRolesForUserId(id)返回LiveData与用户的角色列表.然后在我的片段,我所能做的viewModel.getUserById().observe{}和viewModel.getRolesForUserId().observe{}.但这基本上意味着拥有2名观察员,而且我非常有信心这不是可行的方法.MediatorLiveData 在一个屏幕上有多个不同的数据流是可以的。
一方面,我们可以在不更改用户本身的情况下更改用户角色列表,另一方面,可以在不更新角色列表的情况下更改用户名。使用多个数据流的另一个好处是,您可以在加载用户角色时显示用户数据。
我想,您有用户和角色的 pojo 以避免同步问题。您可以实现平滑的数据传递(从数据库到视图),如下例所示:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
最好将数据源实现封装在Repository类中,并通过 DI 注入,如本段所示。
基于本文中的多对多段落的数据库示例
@Entity(tableName = "users")
public class UsersEntity {
@PrimaryKey
public int id;
public String name;
}
Run Code Online (Sandbox Code Playgroud)
@Entity(tableName = "roles")
public class RolesEntity {
@PrimaryKey
public int id;
public String name;
}
Run Code Online (Sandbox Code Playgroud)
这个实体需要特别注意,因为我们需要声明外键来使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;
}
Run Code Online (Sandbox Code Playgroud)
@Dao
public interface UserDao {
@Query("SELECT * from users WHERE id = :userId")
LiveData<UsersEntity> getUser(int userId);
}
Run Code Online (Sandbox Code Playgroud)
@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);
}
Run Code Online (Sandbox Code Playgroud)
@Database(entities = {UsersEntity.class, RolesEntity.class, UserRolesEntity.class}, version = 1)
public abstract class DataBase extends RoomDatabase {
public abstract UserDao getUserDao();
public abstract RolesDao getRolesDao();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
914 次 |
| 最近记录: |