Andrei Manolache
Andrei Manolache

Reputation: 933

How to fetch data in Room Android using MVVM architecture

So I'm following the MVVM architere where I have a database with banking transactions:

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

I have the Dao class with 2 queries:

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

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

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

ViewModel:

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

In the main fragment, I'm populating a recyclerView with all the transactions in the databse:

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

My question is: How can I call the function from DAO

getTransactionsFiltered(String debtorAccount) 

to populate the SAME recyclerView (when some button is pressed)? I cannot have something like

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

in my DAO because the queries should be done on another thread (I'm NOT allowed to do it on the main thread), so my DAO cannot return a List of transactions.
Can you provide any help?

Upvotes: 0

Views: 1096

Answers (1)

Andrei Manolache
Andrei Manolache

Reputation: 933

ANSWER
This is how I solved it:

Added in Repository class the following function:

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

By doing so, the main thread is not blocked. Don't know for sure if it's the best approach, but it solved my problem

Upvotes: 0

Related Questions