首页 > 解决方案 > 如何使用 MVVM 架构在 Room Android 中获取数据

问题描述

所以我正在关注 MVVM 架构,其中我有一个包含银行交易的数据库:

@Database(entities = {Transaction.class}, version = 1, exportSchema = false) @TypeConverters({DateConverter.class}) 
public abstract class TransactionsRoomDatabase extends RoomDatabase {

        public abstract TransactionDao transactionDao();  
        private static volatile TransactionsRoomDatabase INSTANCE;

        private static final int NUMBER_OF_THREADS = 4;
        private static final ExecutorService databaseWriteExecutor =
                Executors.newFixedThreadPool(NUMBER_OF_THREADS);
    
        public static ExecutorService getDatabaseWriteExecutor() {
            return databaseWriteExecutor;
        }
    
        public static TransactionsRoomDatabase getDatabase(final Context context) {
            if (INSTANCE == null) {
                synchronized (TransactionsRoomDatabase.class) {
                    if (INSTANCE == null) {
                        INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                                TransactionsRoomDatabase .class, "database")
                                .build();
                    }
                }
            }
            return INSTANCE;
        } }

我有 2 个查询的 Dao 类:

@Dao
public interface TransactionDao {
   // first query
    @Query("SELECT * " +
            "FROM transactions_table " +
            "ORDER BY bookingDate, valueDate DESC")
    LiveData<List<Transaction>> getAllTransactions();
  
  // second query that I don't know how to call it in my fragment
    @Query("SELECT * " +
            "FROM transactions_table " +
            "WHERE debtorAccount = :debtorAccount " +
            "ORDER BY valueDate DESC "
    )
    LiveData<List<Transaction>> getTransactionsFiltered(String debtorAccount);

   // insert the list of transactions in databse
   @Insert(onConflict = OnConflictStrategy.REPLACE)
   void insertTransactions(List<Transaction> transactionList);
}

存储库:

public class TransactionRepository {
    private TransactionDao transactionDao;
    private LiveData<List<Transaction>> transactionList;

    public TransactionRepository(Application application) {
        TransactionsRoomDatabase roomDatabase = TransactionsRoomDatabase.getDatabase(application);
        transactionDao = transactionsRoomDatabase.transactionDao();
        transactionList = transactionDao.getAllTransactions();
    }
  
   // get all transactons
   public LiveData<List<Transaction>> getAllTransactions() {
    return transactionList;
   }

   // insert transactions in database using DAO. Are done in another thread so the main thread is not blocked
    public void insertTransactions(List<Transaction> transactionList) {
        TransactionsRoomDatabase.getDatabaseWriteExecutor().execute(() ->       transactionDao.insertTransactions(transactionList));
    }
}

视图模型:

public class HomeAdvancedViewModel extends AndroidViewModel {
    private TransactionRepository transactionRepository;
    private LiveData<List<Transaction>> allTransactions;

    public HomeAdvancedViewModel(Application application) {
        super(application);
        transactionRepository = new TransactionRepository(application);
        allTransactions = transactionRepository.getAllTransactions();
    }

    public LiveData<List<Transaction>> getAllTransactions() {
        return allTransactions;
    }
}

在主要片段中,我使用数据库中的所有事务填充了一个 recyclerView:

public class MainFragment extends Fragment {
    private HomeAdvancedViewModel homeAdvancedViewModel;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        homeAdvancedViewModel = new ViewModelProvider(this).get(HomeAdvancedViewModel.class); // define viewModel
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        /* Here I'm using the observable pattern. When transactions in database are changed, I call my setCurrentTransactions(...) function that populates again the recycler view */
        homeAdvancedViewModel.getAllTransactions().observe(getViewLifecycleOwner(), transactions -> setCurrentTransactions(transactionListAdapter, recyclerViewTransactions, transactions));
    }
}

我的问题是:如何从 DAO 调用函数

getTransactionsFiltered(String debtorAccount) 

填充相同的recyclerView(按下某个按钮时)?我不能有类似的东西

        public void getTransactionsFiltered(String account) {
            TransactionsRoomDatabase.getDatabaseWriteExecutor().execute(() ->       transactionDao.getTransactionsFiltered(account)); // calling the 2nd query in DAO
        }

在我的 DAO 中,因为查询应该在另一个线程上完成(我不允许在主线程上进行),所以我的 DAO 不能返回事务列表。
你能提供任何帮助吗?

标签: androidmvvmandroid-roomdaoandroid-livedata

解决方案


回答
这就是我解决它的方法:

在 Repository 类中添加了以下功能:

public class TransactionRepository {
    private TransactionDao transactionDao;
    private LiveData<List<Transaction>> transactionList;

    public TransactionRepository(Application application) {
        TransactionsRoomDatabase roomDatabase = TransactionsRoomDatabase.getDatabase(application);
        transactionDao = transactionsRoomDatabase.transactionDao();
        transactionList = transactionDao.getAllTransactions();
    }
  
   // get all transactons
   public LiveData<List<Transaction>> getAllTransactions() {
    return transactionList;
   }

   // NEW FUNCTION ADDED
   public LiveData<List<Transaction>> getTransactionsFiltered(String account) {
     return accountsRoomDatabase.transactionDao().getTransactionsFiltered(account);
   }
}

通过这样做,主线程不会被阻塞。不确定这是否是最好的方法,但它解决了我的问题


推荐阅读