我正在尝试使用SQLite数据库存储回收者视图的信息。我希望数据库根据其描述仅包含唯一记录。创建数据库时,我试图将描述字段设置为唯一,但这似乎无济于事。相反,我决定创建一个函数来检查描述是否已经存在于数据库中,然后使用该信息插入新记录。运行调试工具查看我出了问题的地方后,此功能可以正常工作。我认为错误在于db.insert函数,该函数似乎在if语句内部时未执行。任何帮助表示赞赏。
P.S。我对SQLite完全陌生,对周围的行话不太熟悉。
这是该类代码的一部分,可帮助数据库处理
public class DataBaseHandler extends SQLiteOpenHelper {
private final Context context;
public DataBaseHandler(@Nullable Context context) {
super(context, Constants.DB_NAME, null, Constants.DB_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_FOOD_TABLE = "CREATE TABLE " + Constants.TABLE_NAME + "("
+ Constants.KEY_ID + " INTEGER PRIMARY KEY,"
+ Constants.KEY_FOOD_ITEM + " INTEGER,"
+ Constants.KEY_PRICE + " TEXT,"
+ Constants.KEY_QTY_NUMBER + " INTEGER,"
+ Constants.KEY_DESCRIPTION + " TEXT,"
+ Constants.KEY_DATE_NAME + " LONG);";
db.execSQL(CREATE_FOOD_TABLE);
}
这是hasObject函数的代码:
public boolean hasObject(String foodCode) {
SQLiteDatabase db = getWritableDatabase();
String selectString = "SELECT * FROM " + Constants.TABLE_NAME + " WHERE " + Constants.KEY_DESCRIPTION + " =?";
// Add the String you are searching by here.
// Put it in an array to avoid an unrecognized token error
Cursor cursor = db.rawQuery(selectString, new String[] {foodCode});
boolean hasObject = false;
if(cursor.moveToFirst()){
hasObject = true;
}
cursor.close();
db.close();
return hasObject;
}
在单独的类中将这些常量定义为静态的final。
这是存在问题的我的代码。
public void addItem(Item item) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Constants.KEY_FOOD_ITEM, item.getItemName());
values.put(Constants.KEY_PRICE, item.getPrice_double());
values.put(Constants.KEY_QTY_NUMBER, item.getItemQuantity());
values.put(Constants.KEY_DESCRIPTION, item.getDescription());
values.put(Constants.KEY_DATE_NAME,
java.lang.System.currentTimeMillis());//timestamp of the system
// db.insert(Constants.TABLE_NAME, null, values);
// Log.d("DBHandler", "added Item: ");
//Check if the record already exists in the database
if(!hasObject(item.getDescription())){
//Insert the row
db.insert(Constants.TABLE_NAME, null, values); // This is not running as planned
Log.d("DBHandler", "added Item: ");
}
else {
//Don't insert the row
Log.d("DBHandler", "Item exists");
}
}
正如您所注意到的,我尝试按原样运行db.insert函数,而不检查数据库中是否已存在该记录,并且它工作正常。 但是,如果我继续添加记录,无论它们是否在数据库中,都会有太多重复项,这会弄乱回收者视图。
在这里调用additem函数:
databaseHandler= new DataBaseHandler(this);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
itemList= new ArrayList<>();
//tempitemlist = new ArrayList<>();
//Get items from Firebase
mfoodRef.addValueEventListener(new ValueEventListener() {
//Will run everytime there is an update to the condition value in the database
//So this will run when the .setValue function runs in the button onClickListener classes
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
//tempitemlist.clear();
Iterable<DataSnapshot> databaseMenu = dataSnapshot.getChildren();
for (DataSnapshot data:databaseMenu){
Menu tempMenu = data.getValue(Menu.class);
Item tempItem = new Item(tempMenu.getFoodName(),tempMenu.getFoodCode(),tempMenu.getFoodPrice());
//itemList.add(tempItem);
databaseHandler.addItem(tempItem);
}
}
// In case we run into any errors
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
是的,我正在使用Firebase实时数据库中的信息来更新onDataChange方法中数据库处理程序的内容。这就是为什么在插入新记录时需要检查重复项的原因。
编辑:
这是我在调试日志中找到的:
Process: com.example.vendorwrecycler, PID: 12882
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/user/0/com.example.vendorwrecycler/databases/foodList
at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:57)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1567)
at android.database.sqlite.SQLiteDatabase.insertOrThrow(SQLiteDatabase.java:1494)
at com.example.vendorwrecycler.data.DataBaseHandler.addItem(DataBaseHandler.java:68)
at com.example.vendorwrecycler.ListActivity.saveItem(ListActivity.java:184)
at com.example.vendorwrecycler.ListActivity.access$500(ListActivity.java:34)
at com.example.vendorwrecycler.ListActivity$4.onClick(ListActivity.java:159)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
也许与IllegalStateException有关?
答案 0 :(得分:1)
您正在尝试在封闭的DB
实例上执行操作。尝试在SQLiteDatabase db = getWritableDatabase();
语句内移动if
。
if(!hasObject(item.getDescription())){
//Insert the row
SQLiteDatabase db = getWritableDatabase();
db.insert(Constants.TABLE_NAME, null, values);
Log.d("DBHandler", "added Item: ");
}
else {
//Don't insert the row
Log.d("DBHandler", "Item exists");
}
您在DB
函数中关闭了hasObject
的连接。
答案 1 :(得分:0)
tempItem
变量中没有Item tempItem = new Item(tempMenu.getFoodName(),tempMenu.getFoodCode(),tempMenu.getFoodPrice());
。
item.getDescription()
因此tempItem
必须为空或空
记录所有{{1}}对象变量,并确保所有变量都不为null或为空。
希望这会有所帮助