带有LiveData,存储库和ViewModel的Room Database如何一起工作?

时间:2018-07-27 11:09:16

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

我是Android Studio开发的新手,而且大多数工作都很简单。这些概念似乎还很新,而针对它们的Google文档编写得很差,或者使我非常困惑。即使在这里看着其他问题,也不足以为我解决这个问题。

到目前为止,我的应用程序中有一个用户注册或登录,该用户的字符被保存到数据库中或分别从数据库中检索到。在当前状态下,登录和注册以及数据库插入和检索其字符的工作将相应地更新UI。

我有一些片段会改变角色的状态,并且使用ViewModel在角色上使用观察者进行更改后,UI不会更新。另外,数据库也不会使用更改进行更新。

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

我要执行的主要目标是将字符更改保存到数据库中,并使用新更改来更新UI。

编辑:我已经从数据库中删除了回调逻辑,重构了一些我的Dao查询,并相应地更新了repo和viewmodel,并添加了findById查询。我已经使用角色类将数据绑定添加到了我的家庭片段的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:

@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:编辑:通过ID而不是电子邮件找到getPlayer。

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

这段代码是我的家庭片段,其中添加了数据绑定: 编辑:使用getArguments从我的活​​动中获取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);
        }
    });
}

我在第二个片段中具有相同的观察线,并且与此动作类似。它们可以正常运行,只是第一次后不会更新UI。我觉得我对观察者及其应如何调用有错误的方法。编辑:我现在在第二个片段中做了同样的事情,它也可以工作。

1 个答案:

答案 0 :(得分:0)

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