2

In my try to approach to M V VM Architecture I have made this simple Example, and my problem is viewModel don`t show changes that I made to Database, until I restart my app.

1-this is my model class:

@Entity
public class Product {
    @ColumnInfo
    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo
    private String productTitle;

    public Product(String productTitle) {this.productTitle = productTitle;}

    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public String getProductTitle() { return productTitle; }
    public void setProductTitle(String productTitle) { this.productTitle = productTitle; }
}

2-this is DAO

@Dao
public interface ProductDao {
    @Insert   void insert(Product product);
    @Update   void update(Product product);
    @Delete   void delete(Product product);
    @Query("select * from Product")
    List<Product> selectAll();
}

3- this is my AppDatabase:

@Database(entities = { Product.class},version = 1)
public abstract class AppDatabase extends RoomDatabase {

    private static final String DATABASE_NAME = "productDB";
    private static AppDatabase instance;
    public abstract ProductDao getProductDao();

    public static AppDatabase getInstance(Context context){
        if (instance == null) {
            instance = Room.databaseBuilder(context,AppDatabase.class,DATABASE_NAME)
                           .allowMainThreadQueries()
                           .build();}
        return instance;
    }
}

4-this is repository:

public class ProductRepository {
    private ProductDao productDao;
    private List<Product> productList;

    public ProductRepository(Application application) {
        productDao = AppDatabase.getInstance(application).getProductDao();
        productList = productDao.selectAll();
    }
    public void insert (Product myProduct) { productDao.insert(myProduct);}
    public void delete (Product product)   { productDao.delete(product);}
    public void update (Product product)   { productDao.update(product);}
    public List<Product> selectAll()       { return productList;}
}

5-this is ViewModel:

    public ProductViewModel(@NonNull Application application) {
        super(application);
       repository = new ProductRepository(application);
       productList = repository.selectAll();
    }
    public void insert(Product product)  {  repository.insert(product);  }
    public void delete (Product product) {  repository.delete(product);}
    public void update(Product product)  {  repository.update(product);}
    public List<Product> selectAll()     {  return productList;    }
}

and finaly this is the way I used it in main Activity:

.
.
public void btnInsertOnclick(View view) {
        ProductViewModel productViewModel = new ViewModelProvider(this).get(ProductViewModel.class);

        productViewModel.insert(new Product(" product" +String.valueOf(new Random().nextInt(100))  ));

        //-----------> testDB();
        List<Product> testList = productViewModel.selectAll();

        for (Product item : testList) {
            Log.e("dataBaseTest", "CAR #" + item.getId() + " " + item.getProductTitle() + " " );}
    }
.
.

if I use an Instance of repository instead of viewModel to make above Log I can see that change has done to database but viewModel instance dont show the change until I restart my app.

Hadi
  • 124
  • 9

2 Answers2

2

Finally I got the point:

creating ViewModel using "provider" method will generate a "singleton" instance. So on the next instance making of ProductViewModel I will have the old one and as I filled product list in constructor so I will get the old data.

to solve the problem I changed the selectAll method in ProductViewModel as below:

 public List<Product> selectAll()     {  return repository.selectAll();    }
Hadi
  • 124
  • 9
0

I am just curious , Why are you not using LiveData in your case. LiveData will automatically notify you whenever there is a change in your Database related to List.

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

Try like this-

[1]Put all your List into LiveData Holder like below

LiveData<List<Product>>

[2] Make a instance of ViewMoel in onCreate and observe that LiveData variable

productViewModel = new ViewModelProvider(this).get(ProductViewModel.class);
productViewModel.selectAll().observe(getViewLifecycleOwner(), new Observer<List<Product>>() {
        @Override
        public void onChanged(List<Product> testList) {
            for (Product item : testList) {
                Log.d("dataBaseTest", "CAR #" + item.getId() + " " + item.getProductTitle() + "   size : " + testList.size());
            }
        }
    });

[3] then you need only to insert your data in clicklistner.

    private void performAction() {
        productViewModel.insert(new Product(" product" +String.valueOf(new Random().nextInt(100))  ));
    }
  • the reason I did not include LiveData to my project is that after updating database I will close current Activity and the previous Activity simply has informed by intent , so I don`t need to make observable to inform me about database change – Hadi Jul 26 '20 at 19:52
  • ok i got it. But if you use LiveData, it will make thing easier in many ways. – Amitosh Agnihotri Jul 27 '20 at 04:31