如何使用ViewModel,存储库和LiveData访问Room db

时间:2020-07-07 15:39:35

标签: java android android-room android-livedata android-viewmodel

我是android开发的新手。在我的应用程序中,我需要在数据库中有一个用户表。我已经使用room创建了数据库。现在,如果我允许在主线程中运行数据库,则我的应用程序运行良好。但是,我不想在主线程中运行它。因此,我创建了存储库和viewmodel类,并使用viewmodel在主线程中调用db。即使我不将allowMainThreadQueries()放在数据库构建语句中,也会弹出java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.错误。我检查了以下问题: How does the Room Database with LiveData, repository, and viewmodel work together? ,仍然在我的代码中找不到错误。我的代码有什么问题?

我的数据库类:

@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);
        }
    };
}

我的存储库类:

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和实体文件。

2 个答案:

答案 0 :(得分:1)

The documentation解释说:

除非您已执行以下操作,否则房间不支持主线程上的数据库访问 在构建器上称为allowMainThreadQueries(),因为它可能会锁定 用户界面很长一段时间。

这不仅适用于查询,还适用于插入,更新和删除操作。

您正在对主线程执行插入操作

nUserViewModel.insert(newDBUser);

那需要移到后台线程上。

答案 1 :(得分:1)

在数据库类中添加以下内容:

    private static final int NUMBER_OF_THREADS = 4;
    static final ExecutorService databaseWriteExecutor =
            Executors.newFixedThreadPool(NUMBER_OF_THREADS);

在下面的存储库类更改中

    AatchalaDatabase db = AatchalaDatabase.getDatabase(application);


    AatchalaDatabase db = AatchalaDatabase.getinstance(application);

    

在功能下方添加

 `LiveData<List<User>> getAllUsers() {
     AatchalaDatabase.databaseWriteExecutor.execute(() -> {
                mAllUsers = mUserDao.getAllUsers();       
        }
    return mAllUsers;
    }`