SQLite seems not to be executed in Android RecyclerView with onCheckedChanged - java

I have a list inflated by a RecyclerView, which is extracted by an SQLite database. I use a onCheckedChanged to manipulate the data.
If I click the CheckBox, method setItem() is called.
private void setItem(int position, boolean checked) {
// update entries in sqLiteDatabase at click position
// set the database-cursor to current entry
cursor.moveToPosition(position);
// convert boolean to integer, because SQLite does not support boolean values
int iSelected = checked ? 1 : 0;
// create SQL-query-string
String SQLQuery = "" +
"UPDATE country " +
"SET selected=" + iSelected +
" WHERE id='" + cursor.getString(cursor.getColumnIndex("id")) + "'";
// execute the query
sqLiteDatabase.execSQL(SQLQuery);
// create SQL-answer-string
String SQLAnswer = cursor.getString(cursor.getColumnIndex("name")) +
"; Id=" + cursor.getString(cursor.getColumnIndex("id")) +
"; Selected=" + cursor.getString(cursor.getColumnIndex("selected"));
Toast.makeText(context, SQLQuery + "\n\n" + SQLAnswer, Toast.LENGTH_LONG).show();
}
When I click it once on the CheckBox it shows:
SQLQuery => "UPDATE country SET selected=1 WHERE id=3"
SQLAnswer => "Czechia; id=3; selected=1"
When I click it twice:
SQLQuery => "UPDATE country SET selected=0 WHERE id=3"
SQLAnswer => "Czechia; id=3; selected=1"
...and this alters. So the query switches between 0 and 1 (depending on CheckBox), but the answer never becomes 0.
When I close the app and restart it, the database-entries are done well, but it's not updated during runtime.
Has someone an idea (never had such probs with PHP)?

I found a way:
Cursor c = sqLiteDatabase.rawQuery("SELECT * FROM country WHERE id='" + cursor.getString(cursor.getColumnIndex("id")) + "'", null);
c.moveToFirst();
System.out.println(c.getString(c.getColumnIndex("selected")));
Thank you for the comments and help.
I think, that "cursor" was generated in MainAktivity to inflate the adapter, so, fetching a row in the adapter from cursor, will retrieve the state, when the adapter was created and cannot be modified later by the adapter.
I cannot even understand this weird construct with the recyclerView or viewHolder. They changes checkboxes, which are cought by onClickListener, only by scrolling, and the programmer has to correct this mistakes. They are really stupid to handle. In my opinion, a list should be inflated, and the os (android) has to optimized it internally.

Related

delete item from local database function doesn't work

//the following function 'listens to the click' - here we are using an 'item click listener' which gives you a number of which one was clicked
lv_customerList.setOnItemClickListener((parent, view, position, id) -> {
//getting the customer that was just clicked to send it to the method to delete
//the parent of the listener is the listview
CustomerModel clickedCustomer = (CustomerModel) parent.getItemAtPosition(position); //this tells me which person was just clicked
//now we call the "deleteOne" function from the databaseHelper class
dataBaseHelper.deleteOne(clickedCustomer);
//now we update the list view
ShowCustomersOnListView(dataBaseHelper);
Toast.makeText(MainActivity.this, "Deleted" + clickedCustomer,Toast.LENGTH_SHORT).show();
});
This is the code in the MainActivity
//creating a new function that will delete contents from a database
public boolean deleteOne(CustomerModel customerModel) {
//find customerModel in the database. if is is found, delete it and return true, otherwise return false
SQLiteDatabase db = this.getWritableDatabase();
String queryString = "DELETE FROM" + CUSTOMER_TABLE + "WHERE" + CUSTOMER_ID + " = " + customerModel.getId();
Cursor cursor = db.rawQuery(queryString, null);
if (cursor.moveToFirst()) {
return true;
}
else {
return false;
}
}
And this is the code from the DatabaseHelper activity
I followed the https://youtu.be/312RhjfetP8 tutorial and copied the code exactly (although the android IDE suggested to change the...
new AdapterView.OnItemClickListener()
to a lambda (in the method in mainactivity)
But now whenever I click one of the rows (see video to understand what i mean) in the app - the app just crashes and I'm not sure why :(
Could someone please help me out?
Thank you so much!
I'm pretty sure that you miss a lot of space characters in the query String.
String queryString = "DELETE FROM" + CUSTOMER_TABLE + "WHERE" + CUSTOMER_ID + " = " + customerModel.getId();
should be changed to
String queryString = "DELETE FROM " + CUSTOMER_TABLE + " WHERE " + CUSTOMER_ID + " = " + customerModel.getId();
DeleteBuilder<CustomerModel, Integer> deletebuilder =
mcustomermodel.deleteBuilder();

Android SQLite error on cursor

I'm currently working on an android project and am stuck on this method. The cursor query works but anything after that does not. If I take out the 'returnCompany' method it runs so I'm guessing the error is inside the cursor query. The method is taking in a string parameter called 'companyNameParemeter'. FYI Android Studio is the text editor I'm using.
SQLiteDatabase db = this.getReadableDatabase();
String returnString = "";
Cursor cursor = db.rawQuery("Select * from " + CONTANT_INFO_AND_GPS_TABLE + " where " +
KEY_COMPANY_NAME + " = ? ", new String[] {companyNameParamater});
company returnCompany = new company(Integer.parseInt(cursor.getString(0)), cursor.getString(1),
cursor.getString(2), cursor.getString(3),Double.parseDouble(cursor.getString(4) ),
Double.parseDouble(cursor.getString(5)));
/* returnString = ("Company is:\t" + returnCompany.getCompanyName() + ",\nContact name:\t" +
returnCompany.getContactName() + ",\tContact No:\t" + returnCompany.getContactNumber()
+ ",\nGPS:\tLat:\t"
+ returnCompany.getGPS_Latitude() + "\tLong:\t" + returnCompany.getGPS_Longitude() );*/
return returnString;
I checked LogCat and the only relevant error I could find was this
04-04 12:06:38.237 2032-1714/? E/GCoreUlr: Received null location result
Try using
cursor.moveToFirst()
Right AFTER creating and filling it with db.rawquery or wichever call you use to get your data from your DB,
It will make sure your cursor is pointing at the first element you received, i may be wrong but i remember it's always pointing at the end of the data it contains when you fill it.
The error you show doesn't reflect the error you would typically get. However the code you have shown is clearly wrong and would result in an error because you are trying read a row when you are positioned at the start position of the cursor (aka beforeFirstRow).
You have to move to a row before you can get the data. As you only appear to have a single row, then using the Cursor method moveToFirst will either position you at the first (only) row. If the move cannot be made (no rows) then like all the Cursor move????? methods (moveTolast, moveToNext etc) a boolean false is returned (true if the move was made) hence it's use in within the if.
SQLiteDatabase db = this.getReadableDatabase();
String returnString = "";
Cursor cursor = db.rawQuery("Select * from " + CONTANT_INFO_AND_GPS_TABLE + " where " + KEY_COMPANY_NAME + " = ? ", new String[] {companyNameParamater});
if (cursor.moveToFirst()) { //<<<< Move the cursor to a row
company returnCompany = new company(Integer.parseInt(cursor.getString(0)),
cursor.getString(1),
cursor.getString(2),
cursor.getString(3),
Double.parseDouble(cursor.getString(4)),
Double.parseDouble(cursor.getString(5)));
/* returnString = ("Company is:\t" + returnCompany.getCompanyName() + ",\nContact name:\t" +
returnCompany.getContactName() + ",\tContact No:\t" +
returnCompany.getContactNumber()
+ ",\nGPS:\tLat:\t"
+ returnCompany.getGPS_Latitude() + "\tLong:\t" +
returnCompany.getGPS_Longitude() );
*/
}
return returnString;
P.S. Double.parseDouble(cursor.getString(4)) could be cursor.getDouble(4)

Storing data from an entire row, Android SQLite

So I have a method that allows me to get the id of a certain item by using a name i already have in an SQL Database. How would I go about getting the entire row of information and storing each item in its own variable.
Method that only works with ID
public Cursor getID(String name){
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
String query = " SELECT " + COL1 + " FROM " + TABLE_NAME + " WHERE " + COL2 + " = '" + name + "'";
Cursor data = sqLiteDatabase.rawQuery(query, null);
return data;
}
And the method that gets the query and stores the result
Cursor data = mydb2.getID(name);
int itemId= -1;
while(data.moveToNext()){
itemId = data.getInt(0);
}
Using this method below how would i store all of the data in its own variable using this (or any other way to get data of entire row).
public Cursor rowData(String name){
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
String query = " SELECT * FROM " + TABLE_NAME + " WHERE " + COL2 + " = '" + name + "'";
Cursor data = sqLiteDatabase.rawQuery(query, null);
return data;
}
I know this might be a dumb question, and I have tried looking at other questions, I have gotten this far I just don't know what to do next (I'm very new to Sq Lite databases and Android development)
You'd use something like :-
Cursor csr = instance_of_yourdbhelper.rowData();
while(csr.moveToNext()) {
long thisItemId = csr.getLong(csr.getColumnIndex(yourdbhelper.COL_1));
String thisName = csr.getString(csr.getColumnIndex(yourdbhelper.COL_2));
// etc for other columns
}
Notes
yourdbhelper is the class for your DatabaseHelper which is the class that extends SQLiteOpenHelper (the assumption is that the above methods are from such a class, as this is a common usage of SQLite)
instance_of_yourdbhelper is the instance of the DatabaseHelper class i.e. you may have yourdbhelper dbhlpr = new yourdbhelper(parameters);, in which case dbhlpr is the instance.
This just overwrites the same variables (thisItemId and thisName) for each row in the cursor, although there is perhaps the likliehood that the rowData method only returns one row.
You will likely encounter fewer errors using the getColumnIndex method as it returns the offset according to the column name. Miscalculated offsets is a frequent cause of problems.
You may wish to handle a no rows returned situation in which case you can use cursor.getCount(), which will return the number of rows in the cursor.

Retrieving a database value and assigning to a string value

I am making a app that incorporates login/register functionalities and I'm making a issue that I have been trying to solve.
When a user logins and the login is successful, I'd like to use the email that they signed in with to pass to the next activity using Intent (I checked that the email is in fact getting passed by displaying what is being passed through the intent) and then passing that email to a function in the Dbhelper that uses that email to look for the name of the person that signed in then displaying "Welcome (name of person)" in the current activity but I keep getting a null returned in the function which ultimately leads to the app crashing.
Here is where I'm calling the function in the activity where I want to display the name.
if(!session.loggedIn())
{
Logout();
}
else
{
Intent in = getIntent();
String email = in.getStringExtra("email");
Name.setText("Welcome " + db.findName(email));
}
And this is the function in my DbHelper.java where I'm looking for the name with a query and such.
public String findName(String user_email)
{
String query = "SELECT " + COLUMN_NAME + " FROM " + USER_TABLE + " WHERE " + COLUMN_EMAIL + " = " + "'" + user_email + "'";
SQLiteDatabase db = this.getWritableDatabase();
//reads for database
Cursor c = db.rawQuery(query, null);
c.moveToFirst();
if(c.getCount() > 0) // if cursor is not empty
{
String n = c.getString(0);
return n;
}
else
{
return null;
}
}
As you can see, it's returning null. And yes there is entries in the database already. Also, I tried just passing the email to the function and returning what was passed and it still gave me an error.
Normally, to check for a value in a text column, you do not use the equal = sign, but rather WHERE Column LIKE '%text%'. Also, when saving to a database you should escape and "sanitize" strings. If you did this, then you should also be doing the same process when looking for them, else you won't find them.
I am telling you this since, even if you are sure there are entries in your table, the result of the query may be empty. You could just debug by printing the result of the c.getCount() call or something.

How To Test If Cursor Is Empty in a SQLiteDatabase Query

I have an SQL table which is created by the following code:
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + _ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + SUBJECT
+ " TEXT NOT NULL," + TOPIC + " TEXT NOT NULL, "
+ LECTURENUMBER + " TEXT NOT NULL, " + PAGENUMBER
+ " TEXT NOT NULL, " + DATE + " TEXT NOT NULL, " + _DATA
+ " TEXT NOT NULL);");
}
I query the table as follows:
String sql = "SELECT " + _ID + "," + SUBJECT + " FROM " + TABLE_NAME
+ " GROUP BY " + SUBJECT + ";";
Cursor cursor = subjects.getReadableDatabase().rawQuery(sql, null);
The problem is I have to start an Activity A if the cursor is empty(i.e. the table is storing no values) and Activity B if the cursor is not empty(i.e. table is filled).
I am unable to find a method which can tell me if the table is empty or not.
I Have tried to used Log as follows:
private void showSubjectsOnList() {
String sql = "SELECT " + _ID + "," + SUBJECT + " FROM " + TABLE_NAME
+ " GROUP BY " + SUBJECT + ";";
Cursor cursor = subjects.getReadableDatabase().rawQuery(sql, null);
Log.d("Events",Integer.toString(cursor.getCount()));
if(cursor.isNull(0)!=false){
cursor.close();
subjects.close();
startActivity(new Intent(this,OpenScreen.class));
}
}
But the LOG shows 1, if the table is empty...and again 1, if table has 1 entry....it shows 2, if table has two entries and so on.
Can you suggest some method of solving my problem of starting different activities based on if cursor is empty or not.
What about testing the cursor like this, and then doing what you've said:
if(cursor!=null && cursor.getCount()>0)
getCount ()
Returns the numbers of rows in the cursor
http://developer.android.com/reference/android/database/Cursor.html#getCount()
The easiest and cleanest way to test for an empty cursor is the following code:
if ( cursor.moveToFirst() ) {
// start activity a
} else {
// start activity b
}
Per the docs, the method returns false if the cursor is empty:
http://developer.android.com/reference/android/database/Cursor.html#moveToFirst%28%29
public abstract boolean moveToFirst ()
Added in API level 1 Move the cursor to the first row.
This method will return false if the cursor is empty.
Returns whether the move succeeded.
You just need to use getCount().
If your sql is correct but doesn't return any row you will have a NOT null cursor object but without a rows and getCount() will return 0.
Deleted records remain in SQLite as null records, but getCount() counts only not null records. If your table has some records that are null, some of not null records will have _Id numbers bigger than result of getCount(). To reach them, you can iterate cursor ( using for() loop ) double the number of times than result of getCount() and use the cursor to fill record_Id numbers into an array. Lets say resulting array is { 1, 2, 5, 6, 7, 8, 9, 11, 12, 14 }.
That means records 3, 4, 10, 13, are null records and your table has 14 record all together, not 10 that you got from getCount().
Remember:
getCount() returns number of not null records ,
cursor returns _Id numbers of not null records,
_Id numbers "missed" by cursor are _Id numbers of null records,
must reach sufficiently further than getCount() to get them all.
My suggestion would be using a ListActivity.
Those are Activity's which are meant to display items in a ListView. You can simply use a SimpleCursorAdapter to populate them (also illustrated in the ListActivitys JavaDoc page).
They also offer a setEmptyView()-method, which can be used to display a View (might be a TextView) which informs the user that there are no records yet and how he can create one.
An example on how to do that can be found here.
I believe your problem is you're not creating a proper query.
You should use the SQLiteDatabase query.
Cursor c = db.query(TABLE_NAME, null,
null, null, null, null, null);
You then can use c.getCount() to determine if the table has anything.

Categories

Resources