Android ContentValues weird Out of scope removal - android

In a view of my application I can re-sort the position of the rows of a ListView by drag & drop and I save the new order of the rows in the database. The ListView Shows the the contents of an ArrayList defined this way:
ArrayList<ContentValues> lstBat;
and it is populated from a SQLite database. After populate the list I add some values to the "ContentValues" that I use in the Array adapter.
The problem comes in the re_sort method after execute "dbTools.updateBat(cv)".
public void re_sort() {
int lines= lstBat.size();
ContentValues cv=null;
for (int i = 0; i < lines; i++) {
cv = lstBat.get(i); //get row's cv
cv.put("order", i); //Assign new order
dbTools.updateBat(cv); //Store new order in the list
lstBat.set(i, cv);
}
}
The values "state", "icon" and "date" are no longer in the local variable "cv" (ContentValues), they were removed too !!!!!
updateBat method is defined in DBTools class
public int updateBat (ContentValues cv){
SQLiteDatabase database = this.getWritableDatabase();
cv.remove("state"); //Not a column of the table
cv.remove("icon"); //Not a column of the table
cv.remove("date"); //Not a column of the table
return database.update(TABLE_bat, cv, "batId"+"=?", new String[]{cv.getAsString("batId")});
}
And this is the workaround:
public void re_sort() {
int lines= lstBat.size();
long date=0;
String state="";
int icon=0;
ContentValues cv=null;
for (int i = 0; i < lines; i++) {
cv = lstBat.get(i);
date=cv.getAsLong("date");
icon=cv.getAsInteger("icon");
state=cv.getAsString("state");
cv.put("order", i);
dbTools.updateBat(cv);
cv.put("state",state);
cv.put("icon",icon);
cv.put("date",date);
lstBat.set(i, cv);
}
}
If I comment out dbTools.updateBat(cv) the values are preserved, and of course the database won't be updated.
Why were they removed if they are out of scope?

If I correctly understand your code, its behavior seems quite normal.
From your re_sort method you pass the cv object to the updateBat method. All object parameters in Java are passed by reference, therefore cv is NOT a copy of your original object. If you wish to pass a copy of your ContentValues object, you should create a clone. Something like this:
public void re_sort() {
int lines= lstBat.size();
ContentValues cv=null;
for (int i = 0; i < lines; i++) {
cv = lstBat.get(i); //get row's cv
cv.put("order", i); //Assign new order
dbTools.updateBat(new ContentValues(cv)); //Store new order in the list, by passing a new ContentValues object
lstBat.set(i, cv);
}
}

Related

records inserted in a sqlite table are the same for each row

I have a JSONArray which contains many records. I want to compare a string inside those object with a similar(I know it has the same value) record in my SQLite db. but when I loop the table each row value has the first row value.
INSERT A RECORD TO DB >> it returns different value
ArrayList<String> fieldsNameTasse = new ArrayList<String>();
ArrayList<String> fieldsValueTasse= new ArrayList<String>();
for (int i = 0; i < pagamenti.length(); i++) {
JSONObject row = pagamenti.getJSONObject(i); /** LOOP OGGETTI */
String fattura = row.getString("Fattura");
String descrizione = row.getString("Descrizione");
String scadenza = row.getString("Data Scadenza");
String importo = row.getString("Importo");
String stato = row.getString("Stato Pagamento");
// FATURA SHOW ALL DIFFRERENtS VALUE CORRECTLY
fieldsNameTasse.add("fattura");
fieldsValueTasse.add(fattura);
Toast.makeText(getContext(), fattura.toString(), Toast.LENGTH_LONG).show();
fieldsNameTasse.add("descrizione");
fieldsValueTasse.add(descrizione);
fieldsNameTasse.add("scadenza");
fieldsValueTasse.add(scadenza);
fieldsNameTasse.add("importo");
fieldsValueTasse.add(importo);
fieldsNameTasse.add("stato");
fieldsValueTasse.add(stato);
DBmanager.insert("TasseIncoming", fieldsNameTasse, fieldsValueTasse);
}
CHECK DB ROW VALUE << it returns always the first value
/** SHOW ALWAYS THE SAME VALUE*/
int counter = 0;
Cursor cursor = DBmanager.readAll("TasseIncoming");
while(cursor.moveToNext()) {
String ffattura = cursor.getString(cursor.getColumnIndex("fattura"));
counter++;
Toast.makeText(getContext(), ffattura+" - "+counter, Toast.LENGTH_LONG).show();
}
ArrayList<String> fieldsNameTasse = new ArrayList<String>();
ArrayList<String> fieldsValueTasse= new ArrayList<String>();
for (int i = 0; i < pagamenti.length(); i++) {
// add stuff to the above arraylists
DBmanager.insert("TasseIncoming", fieldsNameTasse, fieldsValueTasse);
}
Every time you loop, you're just adding values to the end of what's already in those ArrayLists. So there's lots of duplicate column names with different values for each. Some quick testing:
sqlite> create table foo(a, b);
sqlite> insert into foo(a,b,a,b) values(1,2,3,4);
sqlite> select * from foo;
a b
---------- ----------
1 2
indicates that when a column is included multiple times in an INSERT, only the first corresponding value is used. Hence only ever getting the values from the first iteration of the loop.
The easy fix is to move those variable definitions inside the loop, so each insert is done with a fresh set of columns and values:
for (int i = 0; i < pagamenti.length(); i++) {
ArrayList<String> fieldsNameTasse = new ArrayList<String>();
ArrayList<String> fieldsValueTasse= new ArrayList<String>();
// add stuff to the above arraylists
DBmanager.insert("TasseIncoming", fieldsNameTasse, fieldsValueTasse);
}

how to use the last id SQLite

I am new to the android world and have a problem with an id. What i need is that when the user clicks on new match it will insert a new row into the db. This is working and i get the lastId but now i need this id in the next activities. How can i store that id so i can use it elsewhere?
This is how i insert the new match:
public void newMatch(WedstrijdenGeschiedenis wedstrijd){
// 1.
SQLiteDatabase db = this.getWritableDatabase();
// 2.
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
Date date = new Date();
ContentValues values = new ContentValues();
values.put(KEY_DATUM, dateFormat.format(date)); // get datum
// 3.
long lastId = db.insert(TABLE_WEDSTRIJD, // table
null, //nullColumnHack
values); // key/value -> keys = column names/ values = column values
Log.d("New Match","ID ="+lastId);
// 4. close
db.close();
}
so i see the lastId in LogCat but i don't know how to store it for further use. I tried void but offcourse that is not possible on void. Sorry for the dummy question
change void to long and add a return statement that returns the lastId
public long newMatch(WedstrijdenGeschiedenis wedstrijd){
// Your other code
return lastId;
}
Access it with:
long lastId= db.newMatch(new WedstrijdenGeschiedenis());

How to store data from SQLite in a 2D Arraylist?

I need to get all of the information from my SQLite Database and store it in an Array List, or some other way if there is a better way. My database has 6 columns, here is how I am attempting to extract the data and store it in an Arraylist index;
db.open();
for(int i = 0; i<= amount; i++)
{
Cursor c = db.fetchAllNotes();
if (c.moveToFirst())
{
do {
mid = c.getString(0);
place =c.getString(1);
info =c.getString(2);
coordl1 =c.getString(3);
coordl2 =c.getString(4);
colour =c.getString(5);
//code here to store each string in an Array index
mapSetupList.add(mid,place,info,coordl1,coordl2,colour);
}while (c.moveToNext());
}
}
db.close();
I know how to create an Array list, but I do not know how to store 6 strings in one index, I experimented with 2D Arraylists, but this seemed to be too complicated and I didn't think it was the right way to do it. Is there a better way to do this, if not how can this be done with Arraylists?
What about to create one own defined Object that will wrap all columns as properties?
public class Foo {
private int id; // alternative to id column in db
private String type;
private String date;
...
public void setId(int id) { // setter
this.id = id;
}
public int getId() { // getter
return this.id;
}
}
Then create ArrayList<Foo> and now you can simply save data from SQLite into ArrayList:
public void store() {
Cursor c = null; // first declare and initialise appropriate objects
ArrayList<Foo> foos = new ArrayList<Foo>();
Foo member = null;
try {
c = db.rawQuery(query, whereArgs); // perform query
if (c.moveToFirst()) { // move cursor to first row because implicitly
do { // cursor is position before first row
member = new Foo(); // for each row create new Foo
member.setId(c.getInt(0)); // initialise properties
member.setType(c.getString(1));
member.setDate(c.getString(2));
...
foos.add(member); // add Foo into ArrayList
} while (c.moveToNext()); // it moves cursor to next row
}
}
finally { // in finally block release datasource(s), cursor(s)
if (c != null) {
c.close();
}
if (db != null && db.isOpen()) {
db.close();
}
}
}
Note: I recommend this approach. It's clear, safe and effective. Don't forget to release any datasources, cursors after work is done to avoid usually thrown exceptions like cursor is already open, database is already closed etc.
Update:
I am unsure about the class example, with the defined object and
getters and setters, can you please elaborate before I try this? Thank
you!!
So getters and setters are methods which are used "generaly "for manipulating with properies of Object to preserve Encapsulation - very important thing in OOP. Setters are used for initialising properties and getters for getting properties of Object.
Now i wrote for you example of method for store data from sqlite into ArrayList. There is this line:
member.setId(c.getInt(0));
where setId(c.getInt(0)) is setter of Foo Object with one Integer as parameter and with this method now you will fill up id value with data from Cursor.
Create a Class that contains all the informations that you like, and then create an instance of it then add that instance to the ArrayList.

Android - Speed up inserting data in database

I currently have a CSV file that I parse and am trying to insert the data into the android database. The problem I am having is that it is taking way too long to insert all of the data. It's a good amount of data but I feel like it shouldn't take 20min or so to complete.
Basically, I create my database, then begin the parsing. While parsing through each individual CSV row, I grab the required data and insert it into the database. In total there are around 40000 rows.
Is there any way I can speed up this process? I have tried batch inserts but it never really helped (unless I did it wrong).
Code down below.
Thanks.
DatabaseHelper (i have two insert commands based on the amount of data in each csv row):
// add zipcode
public void add9Zipcode(String zip, String city, String state, String lat,
String longi, String decom) {
// get db and content values
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
db.beginTransaction();
try{
// add the values
values.put(KEY_ZIP, zip);
values.put(KEY_STATE, state);
values.put(KEY_CITY, city);
values.put(KEY_LAT, lat);
values.put(KEY_LONG, longi);
values.put(KEY_DECOM, decom);
// execute the statement
db.insert(TABLE_NAME, null, values);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
db.close();
}
public void add12Zipcode(String zip, String city, String state, String lat,
String longi, String decom, String tax, String pop, String wages) {
// get db and content values
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
db.beginTransaction();
try{
// add the values
values.put(KEY_ZIP, zip);
values.put(KEY_STATE, state);
values.put(KEY_CITY, city);
values.put(KEY_LAT, lat);
values.put(KEY_LONG, longi);
values.put(KEY_DECOM, decom);
values.put(KEY_TAX, tax);
values.put(KEY_POP, pop);
values.put(KEY_WAGES, wages);
// execute the statement
db.insert(TABLE_NAME, null, values);
db.setTransactionSuccessful();
} finally{
db.endTransaction();
}
db.close();
}
Parse File:
public void parse(ArrayList<String> theArray, DatabaseHandler db) {
String[] data = null;
// while loop to get split the data into new lines
// for loop to split each string in the array list of zipcodes
for (int x = 0; x < theArray.size(); x++) {
if(x == 10000 || x == 20000 || x == 30000 || x == 40000){
Log.d(TAG, "x is 10k, 20k, 30k, 40k");
}
// split string first into an array
data = theArray.get(x).split(",");
// separate based on the size of the array: 9 or 12
if (data.length == 9) {
db.add9Zipcode(data[0], data[2], data[3], data[5], data[6],
data[8]);
} else if (data.length == 12) {
db.add12Zipcode(data[0], data[2], data[3], data[5], data[6],
data[8], data[9], data[10], data[11]);
/*
* theZip.zip = data[0]; theZip.city = data[2]; theZip.state =
* data[3]; theZip.lat = data[5]; theZip.longi = data[6];
* theZip.decom = data[8]; theZip. = data[9]; theZip.population
* = data[10]; theZip.wages = data[11];
*/
}
}
Refer to this answer I made previously: Inserting 1000000 rows in sqlite3 database
In short, use an InsertHelper and do more than one insert per transaction - unless you did something wonky, the speed increase should be noticeable.
Edit:
In short:
Your SQLiteOpenHelper should be a singleton used across your entire application.
Don't go around calling close() on your SQLiteDatabase instance - it's cached in the SQLiteOpenHelper and every time you close you force the helper to reopen it.
Batch your inserts, start a transaction outside the call to the addZipCode methods and mark it as successful after you've done all the inserts - then commit the transaction.
Use an InsertHelper - it will format the insert properly as a prepared statement and is nice and reusable.
Be mindful of synchronizing access to the database - unless you intend to do all your database work on the UI-thread (which is not recommended) - you either need to enable locking or guard access to the database to avoid concurrent access.

How do i get data from an SQLITE database to an array in android?

Pretty sure this is an easy one, but i'm getting confused by all the examples that adapt the data returned from a cursor into different views. I just want to run a rawquery and put each item of data returned into a float array (so that i can add them up later). What do i need to use for this? Thanks
You'll still have a cursor when you query your database, but once you got the cursor you could iterate over it, pulling out the values you need into an array, like this:
DbAdapter db = new DbAdapter(mContext);
int columnIndex = 3; // Whichever column your float is in.
db.open();
Cursor cursor = db.getAllMyFloats();
float[] myFloats = new float[cursor.getCount()-1];
if (cursor.moveToFirst())
{
for (int i = 0; i < cursor.getCount(); i++)
{
myFloats[i] = cursor.getFloat(columnIndex);
cursor.moveToNext();
}
}
cursor.close();
db.close();
// Do what you want with myFloats[].
Don't minus by 1 in float[] myFloats = new float[cursor.getCount()-1]; because (int i =0) or i start from 0. If you use it, will appear Java.lang.IndexOutOfBoundsException. You need array index until [cursor.getCount()], not until [cursor.getCount()-1]. So the correct thing is float[] myFloats = new float[cursor.getCount()];

Categories

Resources