Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load multiple AndroidViewModel in a single activity to access LiveData which is returning value from multiple table using Room

I am developing an E-Commerce app in android where I have to create multiple Table, insert data on it and fetch data in activity/fragments from that table (Load value in Spinner, run condition based sub query etc.). For that I declared 2 tables. Address, Bank like below

Bank.java

@Entity
public class Bank {

    @PrimaryKey(autoGenerate = true)
    public int id;
    public String bankId;
    public String bankName;
    public String bankType;

    public Bank() {
    }

    public String getBankId() {
        return bankId;
    }

    public String getBankName() {
        return bankName;
    }

    public String getBankType() {
        return bankType;
    }
}

Address.java

@Entity
public class Address {

    @PrimaryKey(autoGenerate = true)
    public int id;
    public String state;
    public String district;
    public String block;
    public String id_panchayat;
    public String panchayat;

    public Address() {
    }

    public String getState() {
        return state;
    }

    public String getDistrict() {
        return district;
    }

    public String getBlock() {
        return block;
    }

    public String getId_panchayat() {
        return id_panchayat;
    }

    public String getPanchayat() {
        return panchayat;
    }
}

And the Dao class for these two tables are:

BankDao.java

@Dao
public interface BankDao {

    @Insert(onConflict = REPLACE)
    void insertSingleBank (Bank bank);

    @Insert(onConflict = REPLACE)
    void insertMultipleBank (List<Bank> bankList);

    @Query("SELECT * FROM Bank")
    LiveData<List<Bank>> getAllBank();

    @Query("SELECT bankName FROM Bank")
    List<String> getAllBankData ();

    @Query("SELECT * FROM Bank WHERE bankName = :bankName")
    Bank getBankSubData (String bankName);

    @Query("DELETE FROM Bank")
    void deleteBank();
}

AddressDao.java

@Dao
public interface AddressDao {

    @Insert(onConflict = REPLACE)
    void insertSingleAddress(Address address);

    @Insert(onConflict = REPLACE)
    void insertMultipleAddress(List<Address> addressList);

    @Query("SELECT * FROM Address")
    LiveData<List<Address>> getAllAddress();

    @Query("SELECT state FROM Address")
    List<String> getAllStateList();

    @Query("SELECT district FROM Address WHERE state = :state")
    List<String> getDistrictListAll(String state);

    @Query("SELECT block FROM Address WHERE state = :state AND district = :district")
    List<String> getBlockListAll(String state, String district);

    @Query("SELECT panchayat FROM Address WHERE state = :state AND district = :district AND block = :block")
    List<String> getPanchayatListAll(String state, String district, String block);

    @Query("DELETE FROM Address")
    void deleteAddress();
}

And the ViewModel for those two classes are

AddressModel.java

public class AddressModel extends AndroidViewModel {

    private RoomDatabaseHelper roomDatabase;
    private final LiveData<List<Address>> getAllAddress;

    public AddressModel(Application application) {
        super(application);
        roomDatabase = RoomDatabaseHelper.getInstance(this.getApplication());
        getAllAddress = roomDatabase.daoAddress().getAllAddress();
    }

    public void insertSingleAddress(Address address) {
        new InsertSingleAddressAsyncTask(roomDatabase).execute(address);
    }

    private static class InsertSingleAddressAsyncTask extends AsyncTask<Address, Void, Void> {

        private RoomDatabaseHelper db;

        InsertSingleAddressAsyncTask(RoomDatabaseHelper userDatabase) {
            db = userDatabase;
        }

        @Override
        protected Void doInBackground(Address...params) {
            db.daoAddress().insertSingleAddress(params[0]);
            return null;
        }
    }

    public void insertMultipleAddress(List<Address> registrationList) {
        new InsertMultipleAddressAsyncTask(roomDatabase).execute(registrationList);
    }

    private static class InsertMultipleAddressAsyncTask extends AsyncTask<List<Address>, Void, Void> {

        private RoomDatabaseHelper db;

        InsertMultipleAddressAsyncTask(RoomDatabaseHelper userDatabase) {
            db = userDatabase;
        }

        @Override
        protected Void doInBackground(List<Address>...params) {
            db.daoAddress().insertMultipleAddress(params[0]);
            return null;
        }
    }

    public LiveData<List<Address>> getAllAddress() {
        return getAllAddress;
    }
}

BankModel.java

public class BankModel extends AndroidViewModel {

    private RoomDatabaseHelper roomDatabase;
    private final LiveData<List<Bank>> getAllBank;

    public BankModel(Application application) {
        super(application);
        roomDatabase = RoomDatabaseHelper.getInstance(this.getApplication());
        getAllBank = roomDatabase.daoBank().getAllBank();
    }

    public void insertSingleBank(Bank bank) {
        new InsertSingleBankAsyncTask(roomDatabase).execute(bank);
    }

    private static class InsertSingleBankAsyncTask extends AsyncTask<Bank, Void, Void> {

        private RoomDatabaseHelper db;

        InsertSingleBankAsyncTask(RoomDatabaseHelper userDatabase) {
            db = userDatabase;
        }

        @Override
        protected Void doInBackground(Bank...params) {
            db.daoBank().insertSingleBank(params[0]);
            return null;
        }
    }

    public void insertMultipleBank(List<Bank> registrationList) {
        new InsertMultipleBankAsyncTask(roomDatabase).execute(registrationList);
    }

    private static class InsertMultipleBankAsyncTask extends AsyncTask<List<Bank>, Void, Void> {

        private RoomDatabaseHelper db;

        InsertMultipleBankAsyncTask(RoomDatabaseHelper userDatabase) {
            db = userDatabase;
        }

        @Override
        protected Void doInBackground(List<Bank>...params) {
            db.daoBank().insertMultipleBank(params[0]);
            return null;
        }
    }

    public LiveData<List<Bank>> getAllBank() {
        return getAllBank;
    }
}

The RoomDatabase class is

RoomDatabaseHelper.java

@Database(entities = {Address.class, Bank.class}, version = 1, exportSchema = false)
public abstract class RoomDatabaseHelper extends RoomDatabase {

    private static RoomDatabaseHelper sInstance;

    public static synchronized RoomDatabaseHelper getInstance(Context context) {
        if (sInstance == null) {
            sInstance = Room.databaseBuilder(context.getApplicationContext(), RoomDatabaseHelper.class, "DemoTable").build();
        }
        return sInstance;
    }

    public abstract AddressDao daoAddress();

    public abstract BankDao daoBank();
}

and in my Fragment:

BankModel bankModel = ViewModelProviders.of(this).get(BankModel.class);
AddressModel addressModel = ViewModelProviders.of(this).get(AddressModel.class);

Now according to documentation to access the getAllBank() and getAllAddress() from both Model class I have to define like this

addressModel.getAllAddress().observe(mActivity, new Observer<List<Address>>() {
    @Override
    public void onChanged(List<Address> addressList) {
    }
});

addressModel.getAllBank().observe(mActivity, new Observer<List<Bank>>() {
    @Override
    public void onChanged(final List<Bank> bankList) {
    }
});

now both method are AsyncTask like thing. So on activity load I cant change the UI related thing. I have to place the whole UI under onChange. How can I access both observer at the same. Cause nested observer is not the right solution. And also I need many complex database query. So for that I have to define so many observer or is there any other solutions.

like image 612
MaAc Avatar asked Nov 07 '22 06:11

MaAc


1 Answers

First of all, ViewModels should be used as helpers for fragments or activities, to retrieve and process the required data for the views. Thus, one Activity/Fragment should have one viewmodel. And here you use them as some sort of repositories.

If you still wanna use them like that: How can I access both observer at the same

on both onChanged call a method like tryUpdateUi() where you check if both getAllBank().getValue() and getAllAddress().getValue() are not null. If so, you can do the updating/calculations etc.

Although I would prefer doing this check and the data processing in the ViewModel, using another LiveData to pass the processed models to Fragment. It can be achieved with MediatorLiveData, docs

like image 67
Deividas Strioga Avatar answered Nov 15 '22 09:11

Deividas Strioga