添加或删除数据时,房间数据库未正确更新 ID
Room Database does not properly update the ID when data is added or removed
我正在构建一个允许用户存储用户名和密码的应用程序。用户单击 FAB,然后 AddEditEntry.java
activity 开始。用户输入用户名,输入或生成密码,输入提示并单击保存。新数据显示在 Mainactivity.java
中的列表中。如果用户选择编辑条目,所有 s/he 需要做的就是长按该条目,同样 AddEditEntry.java
class 从字段中的先前数据开始。然后用户可以更改该数据并点击保存以更新条目。操作栏上还有一个按钮可以删除所有条目,或者用户可以滑动条目 left/right 将其从数据库中删除。
相反,会发生以下情况:
- 用户能够成功添加新条目。
- 长按后,
AddEditEntry.java
成功地用以前的数据填充字段
- 当用户删除条目时(无论是通过滑动 left/right 还是点击删除所有按钮),新条目不会从 ID 值 1 开始。条目从上一个条目停止的地方开始。因此,如果我删除 ID = 1 的条目,则新条目的 ID = 2.
- 更糟糕的是,当我点击保存按钮 更新 一个条目时,ID 变成了 -1。当发生这种情况时,条目的值根本不存在,因为我在每个状态下使用 Toast 消息检查它们。所以没有更新,条目保持不变。
该应用程序是使用 MVVM 架构构建的,因此我拥有(实体、DAO、数据库、存储库、视图模型)classes,以及必要的适配器 class。我将 post 仅提供相关代码,以尽可能避免混乱。我可以根据请求添加更多代码。
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
//Sends the existing entry for editing
adapter.setOnItemLongClickListener(new RecyclerViewAdapter.OnItemLongClickListener() {
@Override
public void onItemLongClick(Entries entries) {
Intent intent = new Intent(MainActivity.this, AddEditEntry.class);
intent.putExtra(AddEditEntry.EXTRA_USERNAME, entries.getUsername());
intent.putExtra(AddEditEntry.EXTRA_HINT, entries.getHint());
intent.putExtra(AddEditEntry.EXTRA_PASSWORD, entries.getPassword());
intent.putExtra(AddEditEntry.EXTRA_ID, entries.getId());
startActivityForResult(intent, EDIT_ENTRY_REQUEST);
Toast.makeText(MainActivity.this, entries.getUsername(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, entries.getHint(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, entries.getPassword(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, String.valueOf(entries.getId()), Toast.LENGTH_SHORT).show();
}
});
}
...
//The onActivityResult retrieves the result when the user adds
// or edits an entry by checking for the specific request code
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ADD_ENTRY_REQUEST && resultCode == RESULT_OK){
String username = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_USERNAME);
String password = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_PASSWORD);
String hint = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_HINT);
Entries entry = new Entries(username, hint, password);
viewModel.insert(entry);
Toast.makeText(this, "Entry added!", Toast.LENGTH_SHORT).show();
}else if(requestCode == EDIT_ENTRY_REQUEST && resultCode == RESULT_OK){
int id = getIntent().getIntExtra(AddEditEntry.EXTRA_ID, -1);
String username = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_USERNAME);
String password = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_PASSWORD);
String hint = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_HINT);
if (id == -1){Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();}
Entries entry = new Entries(username, hint, password);
entry.setId(id);
viewModel.update(entry);
Toast.makeText(this, String.valueOf(id), Toast.LENGTH_SHORT).show();
Toast.makeText(this, username, Toast.LENGTH_SHORT).show();
Toast.makeText(this, password, Toast.LENGTH_SHORT).show();
Toast.makeText(this, hint, Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Entry updated", Toast.LENGTH_SHORT).show();
}else{Toast.makeText(this, "Entry not added!", Toast.LENGTH_SHORT).show();}
}
AddEditEntry.java
public class AddEditEntry extends AppCompatActivity {
public static final String EXTRA_USERNAME = "com.ozbek.cryptpass.EXTRA_USERNAME";
public static final String EXTRA_HINT = "com.ozbek.cryptpass.EXTRA_HINT";
public static final String EXTRA_PASSWORD = "com.ozbek.cryptpass.EXTRA_PASSWORD";
public static final String EXTRA_ID = "com.ozbek.cryptpass.EXTRA_ID";
public static final int EDIT_ENTRY_REQUEST = 3;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
final Intent intent = getIntent();
// If the ID was passed, gets the extras for editing
if(intent.hasExtra(EXTRA_ID)){
setTitle("Edit Entry");
saveEntry.setText("Update Entry");
usernameEditText.setText(getIntent().getStringExtra(EXTRA_USERNAME));
passwordEditText.setText(getIntent().getStringExtra(EXTRA_PASSWORD));
hintEditText.setText(getIntent().getStringExtra(EXTRA_HINT));
int id = getIntent().getIntExtra(EXTRA_ID, -1);
Toast.makeText(this, "Info Received!!!", Toast.LENGTH_SHORT).show();
Toast.makeText(this, getIntent().getStringExtra(EXTRA_USERNAME), Toast.LENGTH_SHORT).show();
Toast.makeText(this, getIntent().getStringExtra(EXTRA_PASSWORD), Toast.LENGTH_SHORT).show();
Toast.makeText(this, getIntent().getStringExtra(EXTRA_HINT), Toast.LENGTH_SHORT).show();
Toast.makeText(this, String.valueOf(id), Toast.LENGTH_SHORT).show();
}
else{setTitle("Add Entry");}
generatePassword.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {passwordEditText.setText(generatedPassword());}});
saveEntry.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent data = new Intent();
data.putExtra(EXTRA_USERNAME, usernameEditText.getText().toString());
data.putExtra(EXTRA_HINT, hintEditText.getText().toString());
data.putExtra(EXTRA_PASSWORD, passwordEditText.getText().toString());
setResult(RESULT_OK, data);
finish();
}
});
}
...
}
EntryViewModel.java
public class EntryViewModel extends AndroidViewModel {
private EntryRepository repository;
private LiveData<List<Entries>> allEntries;
public EntryViewModel(@NonNull Application application) {
super(application);
repository = new EntryRepository(application);
allEntries = repository.getAllEntries();
}
public void insert(Entries entries){repository.insert(entries);}
public void update(Entries entries){repository.update(entries);}
public void delete(Entries entries){repository.delete(entries);}
public void deleteAll(){repository.deleteAllEntries();}
public LiveData<List<Entries>> getAllEntries() {return allEntries;}
}
Entries.java
@Entity(tableName = "entries_table")
public class Entries {
@PrimaryKey(autoGenerate = true)
private int id;
private String username, hint, password;
public Entries(String username, String hint, String password){
this.username = username;
this.hint = hint;
this.password = password;
}
public Entries(){}
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getHint() {return hint;}
public void setHint(String hint) {this.hint = hint;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
}
When the user deletes an entry (whether through swiping left/right or hitting the delete all button), the new entry does not start from the ID value of 1 onwards. The entry start from where the previous entry left off. So if I delete an entry with the ID = 1, the new entry's ID = 2.
这是自动生成主键的默认行为。有什么问题吗?
Even worse, when I hit the save button to update an entry, the ID becomes -1. And when this happens, the values for the entry do not exist at all because I'm checking them with Toast messages in each state. So there is no updating and the entry remains the same.
我没有阅读所有代码,但这看起来像是一个冲突问题。尝试为您的查询添加替换策略。
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Entries entries);
@Update(onConflict = OnConflictStrategy.REPLACE)
void update(Entries entries);
只需添加这些修复。
在 saveEntry
的 onClick()
中(我假设它是一个按钮)在 AddEditEntry.java
中,将其更改为:
saveEntry.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent data = new Intent();
data.putExtra(EXTRA_USERNAME, usernameEditText.getText().toString());
data.putExtra(EXTRA_HINT, hintEditText.getText().toString());
data.putExtra(EXTRA_PASSWORD, passwordEditText.getText().toString());
//You were missing these 2 lines
int id = getIntent().getIntExtra(EXTRA_ID, -1);
if(id != -1){data.putExtra(EXTRA_ID, id);}
setResult(RESULT_OK, data);
finish();
}
});
然后在 MainActivity.java
中的 onActivityResult
方法中,执行此快速修复:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ADD_ENTRY_REQUEST && resultCode == RESULT_OK){
...
}else if(requestCode == EDIT_ENTRY_REQUEST && resultCode == RESULT_OK){
int id = Objects.requireNonNull(data).getIntExtra(AddEditEntry.EXTRA_ID, -1);
if (id == -1){
Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();
return;
}
...
}else{Toast.makeText(this, "Entry not added!", Toast.LENGTH_SHORT).show();}
}
在这些之后它应该可以工作。如果您有任何问题,请告诉我。
我正在构建一个允许用户存储用户名和密码的应用程序。用户单击 FAB,然后 AddEditEntry.java
activity 开始。用户输入用户名,输入或生成密码,输入提示并单击保存。新数据显示在 Mainactivity.java
中的列表中。如果用户选择编辑条目,所有 s/he 需要做的就是长按该条目,同样 AddEditEntry.java
class 从字段中的先前数据开始。然后用户可以更改该数据并点击保存以更新条目。操作栏上还有一个按钮可以删除所有条目,或者用户可以滑动条目 left/right 将其从数据库中删除。
相反,会发生以下情况:
- 用户能够成功添加新条目。
- 长按后,
AddEditEntry.java
成功地用以前的数据填充字段 - 当用户删除条目时(无论是通过滑动 left/right 还是点击删除所有按钮),新条目不会从 ID 值 1 开始。条目从上一个条目停止的地方开始。因此,如果我删除 ID = 1 的条目,则新条目的 ID = 2.
- 更糟糕的是,当我点击保存按钮 更新 一个条目时,ID 变成了 -1。当发生这种情况时,条目的值根本不存在,因为我在每个状态下使用 Toast 消息检查它们。所以没有更新,条目保持不变。
该应用程序是使用 MVVM 架构构建的,因此我拥有(实体、DAO、数据库、存储库、视图模型)classes,以及必要的适配器 class。我将 post 仅提供相关代码,以尽可能避免混乱。我可以根据请求添加更多代码。
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
//Sends the existing entry for editing
adapter.setOnItemLongClickListener(new RecyclerViewAdapter.OnItemLongClickListener() {
@Override
public void onItemLongClick(Entries entries) {
Intent intent = new Intent(MainActivity.this, AddEditEntry.class);
intent.putExtra(AddEditEntry.EXTRA_USERNAME, entries.getUsername());
intent.putExtra(AddEditEntry.EXTRA_HINT, entries.getHint());
intent.putExtra(AddEditEntry.EXTRA_PASSWORD, entries.getPassword());
intent.putExtra(AddEditEntry.EXTRA_ID, entries.getId());
startActivityForResult(intent, EDIT_ENTRY_REQUEST);
Toast.makeText(MainActivity.this, entries.getUsername(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, entries.getHint(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, entries.getPassword(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, String.valueOf(entries.getId()), Toast.LENGTH_SHORT).show();
}
});
}
...
//The onActivityResult retrieves the result when the user adds
// or edits an entry by checking for the specific request code
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ADD_ENTRY_REQUEST && resultCode == RESULT_OK){
String username = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_USERNAME);
String password = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_PASSWORD);
String hint = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_HINT);
Entries entry = new Entries(username, hint, password);
viewModel.insert(entry);
Toast.makeText(this, "Entry added!", Toast.LENGTH_SHORT).show();
}else if(requestCode == EDIT_ENTRY_REQUEST && resultCode == RESULT_OK){
int id = getIntent().getIntExtra(AddEditEntry.EXTRA_ID, -1);
String username = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_USERNAME);
String password = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_PASSWORD);
String hint = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_HINT);
if (id == -1){Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();}
Entries entry = new Entries(username, hint, password);
entry.setId(id);
viewModel.update(entry);
Toast.makeText(this, String.valueOf(id), Toast.LENGTH_SHORT).show();
Toast.makeText(this, username, Toast.LENGTH_SHORT).show();
Toast.makeText(this, password, Toast.LENGTH_SHORT).show();
Toast.makeText(this, hint, Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Entry updated", Toast.LENGTH_SHORT).show();
}else{Toast.makeText(this, "Entry not added!", Toast.LENGTH_SHORT).show();}
}
AddEditEntry.java
public class AddEditEntry extends AppCompatActivity {
public static final String EXTRA_USERNAME = "com.ozbek.cryptpass.EXTRA_USERNAME";
public static final String EXTRA_HINT = "com.ozbek.cryptpass.EXTRA_HINT";
public static final String EXTRA_PASSWORD = "com.ozbek.cryptpass.EXTRA_PASSWORD";
public static final String EXTRA_ID = "com.ozbek.cryptpass.EXTRA_ID";
public static final int EDIT_ENTRY_REQUEST = 3;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
final Intent intent = getIntent();
// If the ID was passed, gets the extras for editing
if(intent.hasExtra(EXTRA_ID)){
setTitle("Edit Entry");
saveEntry.setText("Update Entry");
usernameEditText.setText(getIntent().getStringExtra(EXTRA_USERNAME));
passwordEditText.setText(getIntent().getStringExtra(EXTRA_PASSWORD));
hintEditText.setText(getIntent().getStringExtra(EXTRA_HINT));
int id = getIntent().getIntExtra(EXTRA_ID, -1);
Toast.makeText(this, "Info Received!!!", Toast.LENGTH_SHORT).show();
Toast.makeText(this, getIntent().getStringExtra(EXTRA_USERNAME), Toast.LENGTH_SHORT).show();
Toast.makeText(this, getIntent().getStringExtra(EXTRA_PASSWORD), Toast.LENGTH_SHORT).show();
Toast.makeText(this, getIntent().getStringExtra(EXTRA_HINT), Toast.LENGTH_SHORT).show();
Toast.makeText(this, String.valueOf(id), Toast.LENGTH_SHORT).show();
}
else{setTitle("Add Entry");}
generatePassword.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {passwordEditText.setText(generatedPassword());}});
saveEntry.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent data = new Intent();
data.putExtra(EXTRA_USERNAME, usernameEditText.getText().toString());
data.putExtra(EXTRA_HINT, hintEditText.getText().toString());
data.putExtra(EXTRA_PASSWORD, passwordEditText.getText().toString());
setResult(RESULT_OK, data);
finish();
}
});
}
...
}
EntryViewModel.java
public class EntryViewModel extends AndroidViewModel {
private EntryRepository repository;
private LiveData<List<Entries>> allEntries;
public EntryViewModel(@NonNull Application application) {
super(application);
repository = new EntryRepository(application);
allEntries = repository.getAllEntries();
}
public void insert(Entries entries){repository.insert(entries);}
public void update(Entries entries){repository.update(entries);}
public void delete(Entries entries){repository.delete(entries);}
public void deleteAll(){repository.deleteAllEntries();}
public LiveData<List<Entries>> getAllEntries() {return allEntries;}
}
Entries.java
@Entity(tableName = "entries_table")
public class Entries {
@PrimaryKey(autoGenerate = true)
private int id;
private String username, hint, password;
public Entries(String username, String hint, String password){
this.username = username;
this.hint = hint;
this.password = password;
}
public Entries(){}
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getHint() {return hint;}
public void setHint(String hint) {this.hint = hint;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
}
When the user deletes an entry (whether through swiping left/right or hitting the delete all button), the new entry does not start from the ID value of 1 onwards. The entry start from where the previous entry left off. So if I delete an entry with the ID = 1, the new entry's ID = 2.
这是自动生成主键的默认行为。有什么问题吗?
Even worse, when I hit the save button to update an entry, the ID becomes -1. And when this happens, the values for the entry do not exist at all because I'm checking them with Toast messages in each state. So there is no updating and the entry remains the same.
我没有阅读所有代码,但这看起来像是一个冲突问题。尝试为您的查询添加替换策略。
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Entries entries);
@Update(onConflict = OnConflictStrategy.REPLACE)
void update(Entries entries);
只需添加这些修复。
在 saveEntry
的 onClick()
中(我假设它是一个按钮)在 AddEditEntry.java
中,将其更改为:
saveEntry.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent data = new Intent();
data.putExtra(EXTRA_USERNAME, usernameEditText.getText().toString());
data.putExtra(EXTRA_HINT, hintEditText.getText().toString());
data.putExtra(EXTRA_PASSWORD, passwordEditText.getText().toString());
//You were missing these 2 lines
int id = getIntent().getIntExtra(EXTRA_ID, -1);
if(id != -1){data.putExtra(EXTRA_ID, id);}
setResult(RESULT_OK, data);
finish();
}
});
然后在 MainActivity.java
中的 onActivityResult
方法中,执行此快速修复:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ADD_ENTRY_REQUEST && resultCode == RESULT_OK){
...
}else if(requestCode == EDIT_ENTRY_REQUEST && resultCode == RESULT_OK){
int id = Objects.requireNonNull(data).getIntExtra(AddEditEntry.EXTRA_ID, -1);
if (id == -1){
Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();
return;
}
...
}else{Toast.makeText(this, "Entry not added!", Toast.LENGTH_SHORT).show();}
}
在这些之后它应该可以工作。如果您有任何问题,请告诉我。