如何使用视图模型、存储库和实时数据访问房间数据库
How to access room db using viewmodel, repository, and livedata
我是 android 开发的新手。在我的应用程序中,我需要在数据库中有一个用户 table。我已经使用房间创建了数据库。现在,如果我允许 运行 主线程中的数据库,我的应用 运行 就可以了。但是,我不想在主线程中 运行 它。因此,我创建了存储库和视图模型 classes 并使用视图模型在主线程中调用数据库。不过,如果我不在数据库构建语句中放入 allowMainThreadQueries()
,则会弹出 java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
错误。我检查了以下问题:
,还是不要在我的代码中发现错误。我的代码有什么问题?
我的数据库class:
@Database(entities = {User.class,Order.class,Items.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {
public abstract UserDao userDao();
public abstract OrderDao orderDao();
public abstract ItemsDao itemsDao();
private static volatile MyDatabase INSTANCE;
public static MyDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (MyDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
MyDatabase.class, "new_database")
.addCallback(sRoomDatabaseCallback).build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
};
}
我的仓库class:
public class UserRepository {
private UserDao mUserDao;
private LiveData<List<User>> mAllUsers;
public UserRepository(Application application){
AatchalaDatabase db = AatchalaDatabase.getDatabase(application);
mUserDao = db.userDao();
}
LiveData<List<User>> getAllUsers() {
return mAllUsers;
}
public void insert(User newDBUser){
mUserDao.addUser(newDBUser);
}
}
我的视图模型:
public class UserViewModel extends AndroidViewModel {
private UserRepository mRepository;
private LiveData<List<User>> mAllUsers;
public UserViewModel(Application application) {
super(application);
mRepository = new UserRepository(application);
mAllUsers = mRepository.getAllUsers();
}
LiveData<List<User>> getAllUsers() {
return mAllUsers;
}
void insert(User user) {
mRepository.insert(user);
}
}
我的部分片段:
public class RegisterFragment extends Fragment implements View.OnClickListener {
private UserViewModel nUserViewModel;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_register, container, false);
Button submitRegister = (Button) rootView.findViewById(R.id.registerSubmit);
submitRegister.setOnClickListener(this);
EditText et = (EditText) rootView.findViewById(R.id.registerDOB);
DatePickerUniversal dob = new DatePickerUniversal(et, "dd-MM-yyyy");
nUserViewModel = new ViewModelProvider(this).get(UserViewModel.class);
return rootView;
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.registerSubmit) {
if (readInput(R.id.registerName).matches("") || readInput(R.id.registerAddress).matches("")
|| readInput(R.id.registerPhone).matches("") || readInput(R.id.registerDOB).matches("")
|| readInput(R.id.registerPassword).matches(""))
showErrorStatus("Please fill all required fields");
else if (!readInput(R.id.registerPassword).equals(readInput(R.id.registerReTypePassword)))
showErrorStatus("Password doesn't match");
else if (!invalidUser(readInput(R.id.registerPhone)))
showErrorStatus("Sorry this mobile number is already registered");
else {
User newDBUser=new User(readInput(R.id.registerPhone), readInput(R.id.registerName),
readInput(R.id.registerDOB), readInput(R.id.registerAddress),
readInput(R.id.registerEmail), readInput(R.id.registerPassword));
Log.d("userdb",newDBUser.toString());
nUserViewModel.insert(newDBUser);
Toast.makeText(getActivity().getApplicationContext(), "Registration successful", Toast.LENGTH_LONG).show();
getActivity().getSupportFragmentManager().popBackStackImmediate();
}
}
}
我还创建了必要的 dao 和实体文件。
The documentation 解释说:
Room doesn't support database access on the main thread unless you've
called allowMainThreadQueries() on the builder because it might lock
the UI for a long period of time.
这也适用于插入、更新和删除操作,而不仅仅是查询。
您正在主线程上执行插入:
nUserViewModel.insert(newDBUser);
需要将其移至后台线程。
在数据库 class 中添加以下内容:
private static final int NUMBER_OF_THREADS = 4;
static final ExecutorService databaseWriteExecutor =
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
在存储库 class 中进行以下更改
AatchalaDatabase db = AatchalaDatabase.getDatabase(application);
AatchalaDatabase db = AatchalaDatabase.getinstance(application);
在函数中添加以下内容
`LiveData<List<User>> getAllUsers() {
AatchalaDatabase.databaseWriteExecutor.execute(() -> {
mAllUsers = mUserDao.getAllUsers();
}
return mAllUsers;
}`
我是 android 开发的新手。在我的应用程序中,我需要在数据库中有一个用户 table。我已经使用房间创建了数据库。现在,如果我允许 运行 主线程中的数据库,我的应用 运行 就可以了。但是,我不想在主线程中 运行 它。因此,我创建了存储库和视图模型 classes 并使用视图模型在主线程中调用数据库。不过,如果我不在数据库构建语句中放入 allowMainThreadQueries()
,则会弹出 java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
错误。我检查了以下问题:
我的数据库class:
@Database(entities = {User.class,Order.class,Items.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {
public abstract UserDao userDao();
public abstract OrderDao orderDao();
public abstract ItemsDao itemsDao();
private static volatile MyDatabase INSTANCE;
public static MyDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (MyDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
MyDatabase.class, "new_database")
.addCallback(sRoomDatabaseCallback).build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
};
}
我的仓库class:
public class UserRepository {
private UserDao mUserDao;
private LiveData<List<User>> mAllUsers;
public UserRepository(Application application){
AatchalaDatabase db = AatchalaDatabase.getDatabase(application);
mUserDao = db.userDao();
}
LiveData<List<User>> getAllUsers() {
return mAllUsers;
}
public void insert(User newDBUser){
mUserDao.addUser(newDBUser);
}
}
我的视图模型:
public class UserViewModel extends AndroidViewModel {
private UserRepository mRepository;
private LiveData<List<User>> mAllUsers;
public UserViewModel(Application application) {
super(application);
mRepository = new UserRepository(application);
mAllUsers = mRepository.getAllUsers();
}
LiveData<List<User>> getAllUsers() {
return mAllUsers;
}
void insert(User user) {
mRepository.insert(user);
}
}
我的部分片段:
public class RegisterFragment extends Fragment implements View.OnClickListener {
private UserViewModel nUserViewModel;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_register, container, false);
Button submitRegister = (Button) rootView.findViewById(R.id.registerSubmit);
submitRegister.setOnClickListener(this);
EditText et = (EditText) rootView.findViewById(R.id.registerDOB);
DatePickerUniversal dob = new DatePickerUniversal(et, "dd-MM-yyyy");
nUserViewModel = new ViewModelProvider(this).get(UserViewModel.class);
return rootView;
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.registerSubmit) {
if (readInput(R.id.registerName).matches("") || readInput(R.id.registerAddress).matches("")
|| readInput(R.id.registerPhone).matches("") || readInput(R.id.registerDOB).matches("")
|| readInput(R.id.registerPassword).matches(""))
showErrorStatus("Please fill all required fields");
else if (!readInput(R.id.registerPassword).equals(readInput(R.id.registerReTypePassword)))
showErrorStatus("Password doesn't match");
else if (!invalidUser(readInput(R.id.registerPhone)))
showErrorStatus("Sorry this mobile number is already registered");
else {
User newDBUser=new User(readInput(R.id.registerPhone), readInput(R.id.registerName),
readInput(R.id.registerDOB), readInput(R.id.registerAddress),
readInput(R.id.registerEmail), readInput(R.id.registerPassword));
Log.d("userdb",newDBUser.toString());
nUserViewModel.insert(newDBUser);
Toast.makeText(getActivity().getApplicationContext(), "Registration successful", Toast.LENGTH_LONG).show();
getActivity().getSupportFragmentManager().popBackStackImmediate();
}
}
}
我还创建了必要的 dao 和实体文件。
The documentation 解释说:
Room doesn't support database access on the main thread unless you've called allowMainThreadQueries() on the builder because it might lock the UI for a long period of time.
这也适用于插入、更新和删除操作,而不仅仅是查询。
您正在主线程上执行插入:
nUserViewModel.insert(newDBUser);
需要将其移至后台线程。
在数据库 class 中添加以下内容:
private static final int NUMBER_OF_THREADS = 4;
static final ExecutorService databaseWriteExecutor =
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
在存储库 class 中进行以下更改
AatchalaDatabase db = AatchalaDatabase.getDatabase(application);
AatchalaDatabase db = AatchalaDatabase.getinstance(application);
在函数中添加以下内容
`LiveData<List<User>> getAllUsers() {
AatchalaDatabase.databaseWriteExecutor.execute(() -> {
mAllUsers = mUserDao.getAllUsers();
}
return mAllUsers;
}`