ViewModel问题,无法在M V VM架构中显示数据库更改。

huangapple go评论75阅读模式
英文:

ViewModel Problem to show Database changes in M V VM Architecture

问题

以下是翻译的内容:

在尝试实现 M V VM 架构时,我创建了这个简单的示例,我的问题是 viewModel 在我对数据库进行更改后不会显示这些更改,除非我重新启动我的应用程序。

1- 这是我的模型类:

@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- 这是 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- 这是我的 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- 这是仓库(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- 这是 ViewModel:

public class ProductViewModel extends AndroidViewModel {
    private ProductRepository repository;
    private List<Product> productList;

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

最后,这是我在主 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() + " ");}
}
// ...

如果我使用 repository 的实例而不是 viewModel,在上述日志中我可以看到对数据库所做的更改,但 viewModel 的实例在我重新启动应用程序之前不会显示更改。

英文:

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(&quot;select * from Product&quot;)
    List&lt;Product&gt; selectAll();
}

3- this is my AppDatabase:

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

    private static final String DATABASE_NAME = &quot;productDB&quot;;
    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&lt;Product&gt; 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&lt;Product&gt; 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&lt;Product&gt; 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(&quot; product&quot; +String.valueOf(new Random().nextInt(100))  ));

        //-----------&gt; testDB();
        List&lt;Product&gt; testList = productViewModel.selectAll();

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

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.

答案1

得分: 2

最终我明白了:

使用“provider”方法创建ViewModel将会生成一个“singleton(单例)”实例。因此,在下一次创建ProductViewModel实例时,我将得到旧的实例,并且由于我在构造函数中填充了产品列表,所以我将获得旧数据。

为了解决这个问题,我将ProductViewModel中的selectAll方法更改如下:

public List<Product> selectAll() { return repository.selectAll(); }
英文:

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&lt;Product&gt; selectAll()     {  return repository.selectAll();    }

答案2

得分: 0

我只是好奇,为什么您在这种情况下不使用 LiveData。LiveData 会在与 List<Product> 相关的数据库发生更改时自动通知您。

> LiveData 是一种可观察的数据持有类。与普通的可观察对象不同,LiveData 具有感知生命周期的特性,这意味着它尊重其他应用程序组件(如活动、片段或服务)的生命周期。这种意识确保 LiveData 仅更新处于活动生命周期状态的应用程序组件观察者。

尝试这样做:

[1] 将您的所有 List 放入 LiveData 持有者中,如下所示:

LiveData<List<Product>>

[2] 在 onCreate 中创建 ViewModel 实例,并观察该 LiveData 变量:

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] 然后您只需要在点击监听器中插入数据:

private void performAction() {
    productViewModel.insert(new Product(" product" +String.valueOf(new Random().nextInt(100))));
}
英文:

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<Product>.

>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&lt;List&lt;Product&gt;&gt;

[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&lt;List&lt;Product&gt;&gt;() {
        @Override
        public void onChanged(List&lt;Product&gt; testList) {
            for (Product item : testList) {
                Log.d(&quot;dataBaseTest&quot;, &quot;CAR #&quot; + item.getId() + &quot; &quot; + item.getProductTitle() + &quot;   size : &quot; + testList.size());
            }
        }
    });

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

    private void performAction() {
        productViewModel.insert(new Product(&quot; product&quot; +String.valueOf(new Random().nextInt(100))  ));
    }

huangapple
  • 本文由 发表于 2020年7月24日 22:08:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/63075299.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定