I am trying to use a SQLite database to store information for a recycler view. I would like the database to contain only unique records according to their description. I have tried to set the description field to unique when I create the database and it does not seem to help. I instead decided to create a function that checks if the description already exists inside the database and then insert the new record with this information. This function works fine, after running the debug tool to see where I went wrong. Where I think the error lies is in the db.insert function that does not seem to execute when inside the if statement. Any help is appreciated.
P.S. I'm a total noob at SQLite and not very familiar with the jargon around it.
Here is part of the code for the class that helps with database handling
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);
}
Here is the code for the hasObject function:
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;
}
The constants are defined in a seperate class as a static final.
Here is my code where the problem exists.
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");
}
}
As you noticed, I tried running the db.insert function just as it is, without checking if the record already exists in the database, and it works fine. But if I keep adding records regardless if they are in the database, there will too many duplicates and this messes up the recycler view.
The additem function is being called here:
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) {
}
});
And yes, I am using the information on my Firebase realtime database to update the contents of the databasehandler in the onDataChange method. Which is why I need to check for duplicates when I am inserting a new record.
EDIT:
This is what I found in the debug log:
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)
Maybe it might be something to do with the IllegalStateException ?
You are trying to execute operation on a closed DB
instance. Try moving SQLiteDatabase db = getWritableDatabase();
inside if
statements.
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");
}
You closed the connection of DB
inside hasObject
function.