带有LiveData,存储库和ViewModel的Room Database如何一起工作? [英] How does the Room Database with LiveData, repository, and viewmodel work together?

查看:82
本文介绍了带有LiveData,存储库和ViewModel的Room Database如何一起工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to Android Studio development and most of it is straight-forward. It seems these concepts are fairly new and Google's documentation for them are either poorly written or just confusing me greatly. Even looking on here at others questions hasn't been sufficient to clear this up for me.

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

What I have so far in my app is a user either registers or logs in where the character of the user gets saved into the database or is retrieved from database respectfully. At the current state the login and registration work with the database inserting and retrieving their character update the UI accordingly.

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

I have fragments that alter the characters stats and the UI does not get updated after changes using an observer on the character using the ViewModel. Also, the database is not updated with the changes either.

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

There are probably simple things I am missing to get this to work. Please let me know of any alterations I should make to the current code and any advice moving forward.

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

The main objective I am trying to do is save the characters changes to the database and have the UI update with the new changes.

我已经从数据库中删除了回调逻辑,重构了一些我的Dao查询,并相应地更新了repo和viewmodel,并添加了findById查询.我已经使用我的角色类将数据绑定添加到了我的家庭片段的xml中.

I have removed the callback logic from the database, refactored some of my Dao queries and updated the repo and viewmodel accordingly, and added a findById query. I have added databinding to my home fragment's xml using my character class.

我的数据库:

@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以进行更新和删除.

My repository: I added asynctasks to update and delete.

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.

My ViewModel: getPlayer is found by id instead of email.

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.为播放器设置内容后,我会更新播放器

This code is my home fragment with the databinding added: Used getArguments to get the Id from my activity, called binding.setPlayer(player) inside onChanged() makes everything work properly updating the database and the UI. After I set something for the player I update the player

    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.我觉得我对观察者及其应如何调用有错误的方法.我现在在第二个片段中做了同样的事情,它也可以工作.

I have the same observe line in my second fragment with similar actions as this one. They function properly the UI just isn't updated after the first time. I feel like I have the wrong approach about the observer and how its supposed to be called. I did the same in my second fragment now and it also works.

推荐答案

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

I figured out how it works now and will update the code accordingly. Maybe someone will find it useful.

这篇关于带有LiveData,存储库和ViewModel的Room Database如何一起工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆