Buckle up folks, this is a weird one. I'm currently working on an android app that involves storing and retrieving data in an sqlite database. I was going through the app and testing some of the basic features to make sure everything worked, and lo and behold I found a bug in retrieving data from my database. When a user inputs their very first entry to the app, everything works as expected, the values get processed and stored. However, when I go back and attempt to access that data using SELECT * FROM history; I get a cursor that returns true when I call data.moveToNext(), yet when I loop through it using while(data.moveToNext()) { //get values and add to a List<> } the while loop never gets executed.
I've looked at the contents of the database after moving the file to my computer and opening the database using this db browser and I can see my entry.
Here's the method that I call to get all the points from my database:
List<PointValue> getAllPoints() {
List<PointValue> points;
Cursor data = rawQuery("SELECT * FROM history");
if (data.moveToNext()) {
points = new ArrayList<>();
while (data.moveToNext()) {
System.out.println("Looped");
long timestamp = data.getLong(data.getColumnIndexOrThrow("timestamp"));
int level = data.getInt(data.getColumnIndexOrThrow("level"));
points.add(new PointValue(timestamp, level));
}
} else {
return null;
}
data.close();
if (points.size() == 0) {
return null;
}
return points;
}
The rawQuery method looks like this:
private Cursor rawQuery(String sql) {
SQLiteDatabase db = this.getReadableDatabase();
return db.rawQuery(sql, null);
}
When I tried debugging this on my own, the size of points is 0 even though I know that there's at least one point in the database. Thoughts? The class containing all of my sql related stuff extends SQLiteOpenHelper
EDIT:
Here's the solution suggested by #Isaac Payne (still doesn't work):
public List<PointValue> getAllPoints() {
List<PointValue> points = new ArrayList<>();
Cursor data = rawQuery("SELECT * FROM history");
while (data.moveToNext()) {
long timestamp = data.getLong(data.getColumnIndexOrThrow("timestamp"));
int level = data.getInt(data.getColumnIndexOrThrow("level"));
points.add(new PointValue(timestamp, level));
}
data.close();
if (points.size() == 0) {
return null;
}
return points;
}
The issue is that when you call data.moveToNext() in the if statement you are moving to the first entry, then you call moveToNext() again in your while loop moving to the second non-existent entry. Try removing the if statement
Add data.moveToFirst() before if loop.
Cursor data = rawQuery("SELECT * FROM history");
//add this line
data.moveToFirst();
if (data.moveToNext()) {
Related
I have an app that inserts data into a database with 2 tables (project and alvara)
The insertion method for the second table depends on what type the first table gets. (1 or 2) for resumed idea.
This is a method that I made for looking into the second table with cursor. If it finds, it sets in setters from alvara_db class. And later on, I use getters to show info on textviews in another activity. The issue is that it's not setting info at all. Is anything wrong in my Cursor?
Thanks in advance!
public ArrayList<alvara_db> getAlvaras(){
SQLiteDatabase db = this.getReadableDatabase();
ArrayList<alvara_db> projects = new ArrayList<>();
String[] project = new String[]{String.valueOf(tipoprojetoid)};
Cursor cur = db.rawQuery("SELECT placa, proj_exec, resp_tec, rtnum, parecer FROM alvara WHERE projetoid = ?", project);
cur.moveToFirst();
alvara_db alvaras = new alvara_db();
alvaras.setPlaca(cur.getInt(cur.getColumnIndex("placa")));
alvaras.setProj_exec(cur.getInt(cur.getColumnIndex("proj_exec")));
alvaras.setResp_tec(cur.getString(cur.getColumnIndex("resp_tec")));
alvaras.setRtnum(cur.getInt(cur.getColumnIndex("rtnum")));
alvaras.setParecer(cur.getString(cur.getColumnIndex("parecer")));
projects.add(alvaras);
return projects;
}
Fragment where I call getAlvaras method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detalhes_projeto_alvara);
db.getAlvaras();
placa = alvaras.getPlaca();
resp_tec = alvaras.getResp_tec();
proj_exec = alvaras.getProj_exec();
rtnum = alvaras.getRtnum();
}
You are not using the returned value from db.getAlvaras().
Instead the alvaras variable in your second snippet is something that is likely not initialized - the code you posted does not show that exactly.
(In addition, you might want to check the return value of moveToFirst() in case the query matches no rows, and add a do-while loop to retrieve more than one row.)
I am trying to fetch all the entries in a database table using SQLite. I ran a query, stored the values in a cursor and then via a loop I fetched all the values. However I can access all the entries except for the first one. Here is my code :
mydb1=new Database_CustomTransaction(getApplicationContext());
Cursor c12 = mydb1.executeQuery("Select * from table1");
System.out.println(c12);
if(c12 == null)
{
TextView nodataView = new TextView(this);
nodataView.setId(20);
nodataView.setText("No Data here !");
nodataView.setTextSize(20);
}
else
{
if(flagValue == false)
{
c12.moveToFirst();
flagValue = true;
}
while(c12.moveToNext())
{
type=c12.getString(0);
amount = c12.getInt(1);
spentOn = c12.getString(2);
date = c12.getString(3);
listType.add(i,type);
listSpentOn.add(i,spentOn);
listAmount.add(i,amount);
listDate.add(i,date);
i++;
}
}
latesttrans2.setAdapter(new TestAdapter2(this, listType, listSpentOn,listAmount,listDate));
Any ideas what I am doing wrong ?
c12.moveToFirst();
This moves to the first row.
while(c12.moveToNext())
This moves to the next row after the first row.
I would guess that the first call should be just dropped, but only you know what you intended with flagValue.
Use do while instead of using just while.I think it is skipping the first entry and straight away moving to next entry.
I've been searching online and trying, but I didn't find the solution.
I have the following ArrayList:
{ Cate1, Cate3, Cate6, Cate2, ...., thru Cate10 }
I gave tried the following solutions:
public ArrayList<String> GetAllCategories_ByAscOrder() {
db = getWritableDatabase();
ArrayList<String> Category_ArrayList = new ArrayList<String>();
Cursor cursor = db.query(Category_TABLE, null, null, null, null, null, Category_List + " ASC");
if(cursor != null)
{
while(cursor.moveToNext())
{
String CATEGORY = cursor.getString(cursor.getColumnIndex(Category_List));
Category_ArrayList.add(CATEGORY);
}
}
cursor.close();
return Category_ArrayList;
}
And these:
Collections.sort(CATEGORY_LIST, new Comparator<String>(){
public int compare(String obj1, String obj2)
{
return obj1.compareToIgnoreCase(obj2);
}
});
}
//OR THIS:
Collections.sort(CATEGORY_LIST, new Comparator<String>(){
public int compare(String obj1, String obj2)
{
return obj1.compareTo(obj2);
}
});
}
//OR THIS:
Collections.sort(CATEGORY_LIST, String.CASE_INSENSITIVE_ORDER);
But ALL of them gave me the same sorting results:
Cate1, Cart10, Cate2, Cate3,, etc.... Cate9
I want the sorted list to be like this:
Cate1 thru Cate10
Can someone please guide me on how I can achieve this?
Thank you very much
Edit:
I forgot to mention that I let the users freely name their Category Names.
do like this :
Collections.sort(list , new Comparator<String>(){
public int compare( String a, String b ){
// if contains number
if( a.substring(4).matches("\\d+") && b.substring(4).matches("\\d+")) {
return new Integer( a.substring(4) ) - new Integer( b.substring(4) );
}
// else, compare normally.
return a.compareTo( b );
}
});
Its sorted by lexicographical order.
If you want it sorted like that, you should switch to using two digits,
eg. Cate01, Cate02, ...
Note that this happens in Windows/Linux filesystems too (if you have numbered files in a folder).
Technically, the results you got are correct - Cart10 alphabetically comes before Cart2 (since 1 comes before 2).
Try adding leading 0s to your numbers before sorting: Cart01, Cart02, etc - though you'll need to pad with leading zeros to make sure you cover the largest you expect your list to get (if it'll be over 100 elements, you'll need more zeros).
Alternatively, why not just store it as ArrayList<Integer> and prepend with "Cart" when you go to output the results? How you ultimately solve this depends on what you want to use the values for...
I have seen a lot of posts on optimizing SQLITE on android with bulk inserts
Currently its taking 90 seconds to do 900 inserts/updates. I added the Begin/End Transaction around them but only saw minor improvements.
So I want to add I believe SQLiteStatement
Here is my code currently
static ArrayList<ContentSystem> csList = new ArrayList<ContentSystem>();
..fill out csList..
_dh.BeginTransaction(Table);
for(int i = 0; i < csList.size(); ++i)
{
addItem(ma, csList.get(i), dh, Table, Key);
}
_dh.setTransactionSuccessful();
_dh.EndTransaction(Table);
public static void addItem(final MainActivity ma, ContentSystem cs,
final DatabaseHandler dh, String Table, String Key)
{
worked = dh.UpdateItem(cs.cv, Table, Key, cs.UUID);
if (worked == 0)
{
worked = dh.AddData(Table, cs.cv);
if (worked <= 0)
{
ErrorLogger.AddError("Error")
}
}
}
My problem is that if my csList contains ~1000 items and some are already in my list, some are not
so I am currently doing a update if the update returns 0 then I do an add
How could I get something like this to work in a bulk statement?
A bit more info
dh.Update
int wok = db.update(table, values, Key + " = ?", new String[] { Item });
dh.Add
int work = (int) db.insert(table, null, values);
ContentSystem is a list of ContentValues
Try INSERT OR REPLACE, instead of either just an update or a failed update followed by an insert.
Are you sure the instantiated SQLiteDatabase object in your DatabaseHandler class is the same as _dh?
You might have started a transaction for _dh, but that might not even be the instantiated object that is actually doing any work.
This is my first time using a database and I'm not really sure how this works. I made the database and made a query that returns a cursor and... now what? What is a cursor, really? Can I just use that to navigate through my data or do I have to put it in an ArrayList or ListActivity or what?
You need to iterate the cursor to get your results.
Use cursor.moveToFirst() and/or cursor.moveToNext() (with a while loop). Then you can use the getX() method, like cursor.getInt() or cursor.getString().
For example, ir your are expecting one result from your query:
if (cursor.moveToFirst()) {
String name = cursor.getString(cursor.getColumnIndex('NAME'));
int age = cursor.getInt(cursor.getColumnIndex('AGE'));
} else {
// oops nothing found!
}
First call cursor.moveToFirst(). Each time you call cursor.moveToNext() it will move to the next row. Make sure when you are done with your cursor you call cursor.deactivate() or you will get errors in your log cat.
Iterate over the returned Cursor instance
public List<Object[]> cursorToTableRows(Cursor cursor) {
List<Object[]> result = new ArrayList<Object[]>(cursor.getCount());
cursor.move(0);
cursor.moveToNext();
while (cursor.isAfterLast() == false) {
Object[] tableRow = new Object[cursor.getColumnCount()];
for(int i=0; i<cursor.getColumnNames().length; i++) {
int columnIndex = cursor.getColumnIndex(cursor.getColumnName(i));
String columnValue = cursor.getString(columnIndex);
tableRow[i] = columnValue;
}
result.add(tableRow);
cursor.moveToNext();
}
cursor.close();
return result;
}
Then create the desired objects.
public List<Vehicle> getVehicles() {
List<Vehicle> vehicles = new ArrayList<Vehicle>();
Cursor cursor = null;
List<Object[]> objects = cursorToTableRows(cursor);
for(Object[] row : objects) {
int i=0;
Vehicle vehicle = new Vehicle(row[i++].toString(), row[i++].toString()));
vehicles.add(vehicle)
}
return vehicles;
}
from Developer.android: This interface provides random read-write access to the result set returned by a database query.
In other words: query returns you a set of data represented by a cursor. First you need to make sure you got a valid cursor (not null) and then try to move it to desired position in the data set (use moveToXXX methods). In order to obtain data pointed by cursor use getXXX methods. When done using it make sure to call close to release resources.
According to this link it looks like you can iterate through the query return using something like:
cursor.next();
And grab the data at the location you are looking for using:
cursor.getString(0)
After you successfully have your Cursor setup, you would typically want to display that to a view in some form.
Have a look at the following answer for a detailed, but simple example of using a Cursor Adapter to pair up your newly-minted Cursor with your desired XML View:
https://stackoverflow.com/a/20532937/293280