会议室数据库:创建新的RecyclerView项后两次获得SELECT MAX() [英] Room database: getting SELECT MAX() twice after creating new RecyclerView item

查看:99
本文介绍了会议室数据库:创建新的RecyclerView项后两次获得SELECT MAX()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个正常工作的CardView项目的RecyclerView列表.创建插入数据库中的新CardView之后,我想触发一个Toast,该Toast通知用户CardView已成功添加,并显示CardView编号. CardView号是插入数据库中的CardView项的ID.当用户单击触发onClickSave()的保存"按钮时,数据将保存到数据库中.

I have a RecyclerView list of CardView items that is working properly. Upon creation of a new CardView that is inserted into the database, I would like to fire a Toast that informs the user that the CardView was successfully added and show the CardView number. The CardView number is the Id of the CardView item inserted into the database. The data is saved to the database when the user clicks on a Save button that fires onClickSave().

我在Dao中设置了一个@Query以获取MAX(cardId):

I set up an @Query in the Dao to get the MAX(cardId):

Dao
...
@Query("SELECT MAX(cardId) FROM cards")
LiveData<Integer> getMax();

@Insert
void insertCard(Card card);

问题是两个烤面包都在开火.第一个Toast返回先前创建的CardView编号,然后,然后第二个Toast触发,并显示刚添加的最新CardView编号.例如,Toast将显示CardView编号33,然后第二次Toast触发,显示刚刚创建的预期CardView编号34(我使用数据库浏览器来确认CardViews 33和34都在数据库中,并且是两个最高的项. SQLite软件).

Problem is that two Toasts are firing. The first Toast is returning the previously created CardView number and then the second Toast is firing and it shows the latest CardView number that was just added. For example, the Toast will show CardView number 33 and then a second Toast fires that shows the expected CardView number 34 that was just created (I confirm that CardViews 33 and 34 are both in the database and the two highest items, using DB Browser for SQLite software).

AddorUpdateCardActivity
...
private int newMax = -1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mViewModel = new ViewModelProvider(this).get(cardViewModel.class);        
}

public void onClickSave(View v) {

    // set card data
    // then insert data in database
    mViewModel.insertCard(card1);     

    mViewModel.getMax().observe(this, value -> { newMax = value; Toast.makeText(AddorUpdateCardActivity.this, "card #" + newMax + " was saved to the list", Toast.LENGTH_LONG).show();});
}

ViewModel
...

public cardViewModel(Application application) {
    super(application);
    repository = new cardRepository(application);
    getMax = repository.getMax();
}

public LiveData<Integer> getMax() {
    return getMax;
}

public void insertCard(Card card) {
    repository.insertCard(card);
}

cardRepository

private CardDao cardDao;
private LiveData<Integer> getMax;


public cardRepository(Application application) {
    RoomDatabase db = RoomDatabase.getDatabase(application);
    cardDao = db.cardDao();
}

public LiveData<Integer> getMax() {
    return cardDao.getMax;  
}

public void insertCard(Quickcard newcard) {
    AsyncTask.execute(() -> cardDao.insertCard(newcard));

} 

我在这里想念什么?如果将卡正确插入数据库,那么ViewModel观察器为什么不返回这个新的CardView号而不是两个Toasts?

What am I missing here? If the card is inserted properly into the database then why wouldn't the ViewModel observer just return this new CardView number rather than two Toasts?

作为参考,我显示了在Room和ViewModel之前使用的先前代码,该代码使用游标获取最新和最高的插入ID:

For reference, I show the previous code I used prior to Room and ViewModel that used a cursor to get the latest and highest inserted Id:

public class SQLiteDB extends SQLiteOpenHelper {

    ...
    public int getLastInsertId() {

    int index = 0;
    SQLiteDatabase sdb = getReadableDatabase();
    Cursor cursor = sdb.query(
            "sqlite_sequence",
            new String[]{"seq"},
            "name = ?",
            new String[]{TABLE_NAME},
            null,
            null,
            null,
            null
    );

    sdb.beginTransaction();
    try {
        if (cursor !=null) { 
            if (cursor.moveToLast()) {                    
                index = cursor.getInt(cursor.getColumnIndex("seq"));
            }
        }
    ...
    }         
    return index;
}      

推荐答案

您在onClickSave中调用的视图模型操作是异步的:

The view model operations you call within onClickSave are asynchronous:

public void onClickSave(View v) {
    mViewModel.insertCard(card1);
    mViewModel.getMax().observe(this, value -> { newMax = value; makeText(AddorUpdateCardActivity.this, "TEXT", .LENGTH_LONG).show();});
}

LiveData的实现记录了数据版本以及观察者看到的最后一个版本.

The implementation of LiveData records the data version as well as the last version seen by the observer.

因此,当您开始使用新创建的观察器从主线程观察getMax时,insertCard开始在工作线程上运行.这样,在更新数据库后,您将收到当前值以及新值.

Therefore insertCard starts to operate on a worker thread while you start observing getMax from the main thread with a newly created observer. Thus you'll receive the current value as well as the new value after the database was updated.

相反,您只能在onCreate()中观察一次,然后等待数据库触发的更新:

Instead you could observe it only once in onCreate() and wait for the updates triggered by the database:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mViewModel = new ViewModelProvider(this).get(cardViewModel.class);
    mViewModel.getMax().observe(this, value -> { newMax = value; makeText(AddorUpdateCardActivity.this, "TEXT", .LENGTH_LONG).show();});
}

public void onClickSave(View v) {
    mViewModel.insertCard(card1);
}

这篇关于会议室数据库:创建新的RecyclerView项后两次获得SELECT MAX()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆