android - 带有 LiveData、存储库和 View 模型的房间数据库如何协同工作?

标签 android database android-studio android-room android-livedata

我是 Android Studio 开发的新手,其中大部分都是直截了当的。似乎这些概念是相当新的,谷歌的文档要么写得不好,要么让我很困惑。即使在这里看其他问题也不足以为我解决这个问题。

到目前为止,我的应用程序中的用户要么注册要么登录,用户的角色被保存到数据库中或从数据库中检索出来。在当前状态下,登录和注册工作与数据库插入和检索他们的角色相应地更新 UI。

我有 fragment 会更改角色统计信息,并且在使用 ViewModel 对角色进行更改后,UI 不会更新。此外,数据库也不会随更改而更新。

我可能缺少一些简单的东西来让它工作。请让我知道我应该对当前代码进行的任何更改以及任何向前推进的建议。

我想要做的主要目标是将字符更改保存到数据库并使用新更改更新 UI。

编辑:我已经从数据库中删除了回调逻辑,重构了我的一些 Dao 查询并相应地更新了 repo 和 viewmodel,并添加了一个 findById 查询。我已经使用我的字符类将数据绑定(bind)添加到我的主 fragment 的 xml 中。

我的数据库:

@Database(entities = {Character.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {

    public abstract UserDao userDao();

    private static 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, "character_database")
                           .build();
                }
           }
       }
       return INSTANCE;
    }
}

我的道:
@Dao        //Data Access Object
public interface UserDao {

    @Query("SELECT * FROM character_table")
    LiveData<List<Character>> getAllCharacters();

    @Query("SELECT * FROM character_table WHERE email LIKE :email LIMIT 1")
    LiveData<Character> findByEmail(String email);

    @Query("SELECT * FROM character_table WHERE name")
    LiveData<List<Character>> sortByName();

    @Query("SELECT * FROM character_table WHERE id LIKE :id LIMIT 1")
    LiveData<Character> findById(int id);

    @Query("SELECT * FROM character_table WHERE rank")
    LiveData<List<Character>> sortByRank();

    @Query("SELECT * FROM character_table WHERE total_exp")
    LiveData<List<Character>> sortByExp();

    @Query("SELECT * FROM character_table WHERE village")
    LiveData<List<Character>> sortByVillage();

    @Query("SELECT * FROM character_table WHERE email LIKE :email AND password LIKE :password")
    LiveData<Character> login(String email, String password);

    @Delete
    void deleteCharacter(Character player);

    @Query("DELETE FROM character_table")
    void deleteAll();

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void save(Character player);

    @Update
    void update(Character player);

我的存储库:编辑:我添加了 asynctasks 来更新和删除。
public class CharacterRepository {

    private final UserDao userDao;
    private LiveData<List<Character>> allCharacters;
    private LiveData<List<Character>> sortByName;
    private LiveData<List<Character>> sortByExp;
    private LiveData<List<Character>> sortByRank;
    private LiveData<List<Character>> sortByVillage;

    CharacterRepository(Application application){
        MyDatabase db = MyDatabase.getDatabase(application);
        userDao = db.userDao();
        allCharacters = userDao.getAllCharacters();
        sortByName = userDao.sortByName();
        sortByExp = userDao.sortByExp();
        sortByRank = userDao.sortByRank();
        sortByVillage = userDao.sortByVillage();
    }

    public LiveData<Character> login(String email, String password){
        return userDao.login(email, password);
    }

    LiveData<List<Character>> sortByName(){
        return sortByName;
    }

    LiveData<Character> findByEmail(String email){
        return userDao.findByEmail(email);
    }

    LiveData<List<Character>> sortByName(){
        return sortByName;
    }

    LiveData<List<Character>> sortByExp(){
        return sortByExp;
    }

    LiveData<List<Character>> sortByRank(){
        return sortByRank;
    }

    LiveData<List<Character>> sortByVillage(){
        return sortByVillage;
    }

    LiveData<List<Character>> getAll(){
        return allCharacters;
    }

    public void insert(Character player){
        new insertAsyncTask(userDao).execute(player);
    }

    public void update(Character player){
        new updateAsyncTask(userDao).execute(player);
    }

    public void delete(Character player){
        new deleteAsyncTask(userDao).execute(player);
    }

    public LiveData<Character>  getPlayer(String id){
        return userDao.findByEmail(id);
    }

    private static class insertAsyncTask extends AsyncTask<Character, Void, Void> {

        private UserDao mAsyncTaskDao;

        insertAsyncTask(UserDao dao) {
            mAsyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(Character... characters) {
            mAsyncTaskDao.save(characters[0]);
            return null;
        }
    }

    private static class updateAsyncTask extends AsyncTask<Character, Void, Void> {

        private UserDao mAsyncTaskDao;

        updateAsyncTask(UserDao dao) {
            mAsyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(Character... characters) {
            mAsyncTaskDao.update(characters[0]);
            return null;
        }
    }

    private static class deleteAsyncTask extends AsyncTask<Character, Void, Void> {

        private UserDao mAsyncTaskDao;

        deleteAsyncTask(UserDao dao) {
            mAsyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(Character... characters) {
            mAsyncTaskDao.deleteCharacter(characters[0]);
            return null;
        }
    }
}

我的 ViewModel:编辑:getPlayer 是通过 id 而不是电子邮件找到的。
public class MyViewModel extends AndroidViewModel {

    private CharacterRepository cRepository;
    private LiveData<List<Character>> allCharacters;

    public MyViewModel(Application application){
        super(application);
        cRepository = new CharacterRepository(application);
        allCharacters = cRepository.getAll();
    }

    LiveData<List<Character>> getAllCharacters() {return allCharacters;}

    public void insert(Character player){
        cRepository.insert(player);
    }

    public void deletePlayer(Character player){
        cRepository.delete(player);
    }

    public void updatePlayer(Character player){
        cRepository.update(player);
    }

    public LiveData<Character> getPlayer(int id){
        return cRepository.getPlayer(id);
    }

    public LiveData<Character> findByEmail(String email){
        return cRepository.findByEmail(email);
    }

    public LiveData<Character> login(String email, String password){
        return cRepository.login(email, password);
    }
}

这段代码是我添加了数据绑定(bind)的主 fragment :
编辑:使用 getArguments 从我的 Activity 中获取 Id,在 onChanged() 中调用 binding.setPlayer(player) 使一切正常工作,更新数据库和 UI。在我为播放器设置了一些东西后,我更新了播放器
    private MyViewModel viewModel;
    private FragmentHomeBinding binding;
    private View rootView;
    private Character player;
    private int id;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, 
                             @Nullable ViewGroup container, 
                             @Nullable Bundle savedInstanceState) {
    binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false);
    rootView = binding.getRoot();
    viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
    id = getArguments().getInt("id"); 
    return rootView;
}

@Override
public void onStart() {
    super.onStart();

    // Home fragment buttons.
    final Button sleepButton = getView().findViewById(R.id.sleepButton);
    final Button bankButton  = getView().findViewById(R.id.bankButton);
    final Button infoButton  = getView().findViewById(R.id.infoButton);

    // The view that shows the players pool ratio.
    info = getView().findViewById(R.id.poolAmount);
    layout = getView().findViewById(R.id.poolInfo);

    // The players status bars.
    healthBar = getView().findViewById(R.id.healthBar);
    chakraBar = getView().findViewById(R.id.chakraBar);
    staminaBar = getView().findViewById(R.id.staminaBar);

    //Observe LiveData Character.
    viewModel.getPlayer(id).observe(this, new Observer<Character>() {
        @Override
        public void onChanged(@Nullable final Character character) {
            player = character;
            player.setRank(updateRank());
            binding.setPlayer(player);

            //Setting the progress and max for each user pool.
            healthBar.setProgress((int)player.getHealth());
            healthBar.setMax((int)player.getHealthMax());

            chakraBar.setProgress((int)player.getChakra());
            chakraBar.setMax((int)player.getChakraMax());

            staminaBar.setProgress((int)player.getStamina());
            staminaBar.setMax((int)player.getStaminaMax());

        }
    });

    sleepButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            if (player.isAwake()) {
                player.setAwake(false);
                sleepButton.setText("Wake Up");
                Toast.makeText(getContext(), "You went to sleep...", Toast.LENGTH_SHORT).show();
            } else {
                player.setAwake(true);
                sleepButton.setText("Sleep");
                Toast.makeText(getContext(), "You woke up!", Toast.LENGTH_SHORT).show();
            }
        }
    });

    bankButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
            final View bankPrompt = getLayoutInflater().inflate(R.layout.bank_prompt, null);
            builder.setView(bankPrompt);

            final AlertDialog dialog = builder.create();
            dialog.show();

            TextView bankMoney = bankPrompt.findViewById(R.id.bankAmount);
            TextView pocketMoney = bankPrompt.findViewById(R.id.pocketAmount);
            Button depositButton = bankPrompt.findViewById(R.id.depositButton);
            Button withdrawButton = bankPrompt.findViewById(R.id.withdrawButton);
            ImageButton closeBankPrompt = bankPrompt.findViewById(R.id.closeBank);

            pocketMoney.setText(String.valueOf(player.getPocketMoney()));
            bankMoney.setText(String.valueOf(player.getBankMoney()));

            depositButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    final View transactionPrompt = getLayoutInflater()
                            .inflate(R.layout.bank_transaction, null);
                    builder.setView(transactionPrompt);
                    TextView transactionText = transactionPrompt.findViewById(R.id.bankTransactionText);
                    transactionText.setText(R.string.bank_deposit);

                    final AlertDialog dialog = builder.create();

                    dialog.show();
                    Button confirmDeposit = transactionPrompt.findViewById(R.id.confirmTransaction);
                    ImageButton closePrompt = transactionPrompt.findViewById(R.id.cancelTransaction);

                    confirmDeposit.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            bankTransaction(player,0, transactionPrompt, bankPrompt);
                            dialog.hide();
                        }
                    });

                    closePrompt.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            dialog.hide();
                        }
                    });
                }
            });

            withdrawButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    final View transactionPrompt = getLayoutInflater()
                            .inflate(R.layout.bank_transaction, null);
                    builder.setView(transactionPrompt);

                    TextView transactionText = transactionPrompt.findViewById(R.id.bankTransactionText);
                    transactionText.setText(R.string.bank_withdraw);

                    final AlertDialog dialog = builder.create();

                    dialog.show();
                    Button confirmWithdraw = transactionPrompt.findViewById(R.id.confirmTransaction);
                    ImageButton closePrompt = transactionPrompt.findViewById(R.id.cancelTransaction);

                    confirmWithdraw.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            bankTransaction(player,1, transactionPrompt, bankPrompt);
                            dialog.hide();
                        }
                    });

                    closePrompt.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            dialog.hide();
                            }
                    });
                }
            });

            closeBankPrompt.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialog.hide();
                }
            });
        }
    });

    infoButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ScrollView info = getView().findViewById(R.id.infoView);

            if (info.getVisibility() == View.VISIBLE)
                info.setVisibility(View.GONE);
            else
                info.setVisibility(View.VISIBLE);
        }
    });
}

在我的第二个 fragment 中,我有相同的观察线,具有与这个相似的 Action 。它们正常运行,用户界面在第一次之后没有更新。我觉得我对观察者以及应该如何调用它的方法有误。编辑:我现在在我的第二个 fragment 中做了同样的事情,它也有效。

最佳答案

我弄清楚了它现在是如何工作的,并将相应地更新代码。也许有人会发现它很有用。

关于android - 带有 LiveData、存储库和 View 模型的房间数据库如何协同工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51556717/

相关文章:

android - 在应用程序结果中添加UsbSerialForAndroid库导致Gradle错误

mysql - 如何使用 GORM 创建递归关联?

php - 使用一个事务 ID 在数据库中进行多次插入

android - Android Studio:将YouTube channel 供稿插入我的应用程序?

java - Android Studio : Error:/android-studio/gradle/gradle-2. 4/lib/plugins/gradle-diagnostics-2.4.jar(没有这样的文件或目录)

android - 无法使用当前运行时配置初始化org.apache.velocity.runtime.log.CommonsLogLogChute实例

android - CSS 位置 :fixed causes blurry images in Android Browsers

android - android构建系统中不再有Android.mk吗?

android - 如何在 Android 上获取默认颜色

database - 如何在用户提交表单后自动生成网页