Android - populate ListView SQLite, cursor null pointer - android

I have two tables atm, users and notes. I am trying to retrieve data that belongs to the user. So all data to list must be owned by the original user and shown only to him. I have made my table in Databasehelper.
I have made a new class that controls the notes table. In listNotes() I want to loop through the cursor row and get all data owned by the user. Am I quering it correctly?
// Listing all notes
public Cursor listNotes() {
Cursor c = db.query(help.NOTE_TABLE, new String[]{help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE}, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
db.close();
return c;
}
I then want to display the cursor data collected in a listview
public void populateList(){
Cursor cursor = control.listNotes();
getActivity().startManagingCursor(cursor);
//Mapping the fields cursor to text views
String[] fields = new String[]{help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE};
int [] text = new int[] {R.id.item_title,R.id.item_body, R.id.item_date};
adapter = new SimpleCursorAdapter(getActivity(),R.layout.list_layout,cursor, fields, text,0);
//Calling list object instance
listView = (ListView) getView().findViewById(android.R.id.list);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
}

You aren't creating the NOTE_TABLE right.
You miss a space and a comma here
+ COLUMN_DATE + "DATETIME DEFAULT CURRENT_TIMESTAMP"
It has to be
+ COLUMN_DATE + " DATETIME DEFAULT CURRENT_TIMESTAMP,"

There are two issues here:
One is you have missed a comma (after the Timestamp as specified in an earlier answer).
The other error you have is when using a SimpleCursorAdapter, you need to ensure that the Projection string array includes something to index the rows uniquely and this must be an integer column named as "_id". SQLite already has a feature built in for this and provides a column named "_id" for this purpose (however you can have your own integer column which you can rename to _id). To solve this, change your projection string array to something like:
new String[] {"ROW_ID AS _id", help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE}
I guess the NullPointerException stems from this (but without the stacktrace I don't know for sure).

Related

Why Sqlite return only last row not all rows data?

I don't know what's wrong with my code I follow the rule but I get wrong result. I want to search db and find all rows data but I only get last row from sqlite. my code to search database is bellow:
public ArrayList<ArrayList<ContractSaveDataFromDB>> ActiveContractData(String phone, String numberId)
{
ArrayList<ContractSaveDataFromDB> UserData = new ArrayList<ContractSaveDataFromDB>();
ArrayList<ArrayList<ContractSaveDataFromDB>> SendUserData =
new ArrayList<ArrayList<ContractSaveDataFromDB>>();
SQLiteDatabase db = this.getReadableDatabase();
String whereClause = "phone = ? AND numberId = ?";
String[] whereArgs = new String[]{
phone,
numberId
};
String orderBy = "activeContract";
Cursor res2=db.query("usersAccount",null,whereClause,whereArgs,null,null,orderBy);
res2.moveToFirst();
do{
UserData.clear();
int index;
ContractSaveDataFromDB contractSaveDataFromDB=new ContractSaveDataFromDB();
index = res2.getColumnIndex("buyAmount");
String buyAmount = res2.getString(index);
contractSaveDataFromDB.setBuyAmount(buyAmount);
UserData.add(contractSaveDataFromDB);
SendUserData.add(UserData);
} while(res2.moveToNext());
res2.close();
db.close();
return SendUserData;
I don't know what's wrong. I appreciate if you help me to solve my problem.
you already added where clause so maybe it is filtering your results try to remove it by change this
Cursor res2=db.query("usersAccount",null,whereClause,whereArgs,null,null,orderBy);
to this
Cursor res2=db.query("usersAccount",null,null,null,null,null,orderBy);
I believe that your issues is that you are trying to use an ArrayList of ArrayList of ContractSaveDataFromDB objects.
I believe that an ArrayList of ContractSaveDataFromDB objects would suffice.
It would also help you if you learnt to do a bit of basic debugging, as an issue could be that you are not extracting multiple rows.
The following is an alternative method that :-
uses the ArrayList of ContractSaveDataFromDB objects,
introduces some debugging by the way of writing some potentially useful information to the log
and is more sound, as it will not crash if no rows are extracted
i.e. if you use moveToFirst and don't check the result (false means the move could not be accomplished) then you would get an error because you are trying to read row -1 (before the first row) as no rows exists in the cursor.
:-
public ArrayList<ContractSaveDataFromDB> ActiveContractData(String phone, String numberId) {
ArrayList<ContractSaveDataFromDB> SendUserData = new ArrayList<ContractSaveDataFromDB>();
SQLiteDatabase db = this.getReadableDatabase();
String whereClause = "phone = ? AND numberId = ?";
String[] whereArgs = new String[]{
phone,
numberId
};
String orderBy = "activeContract";
Cursor res2 = db.query("usersAccount", null, whereClause, whereArgs, null, null, orderBy);
Log.d("RES2 COUNT", "Number of rows in Res2 Cursor is " + String.valueOf(res2.getCount()));
while (res2.moveToNext()) {
ContractSaveDataFromDB current_user_data = new ContractSaveDataFromDB();
current_user_data.setBuyAmount(res2.getString(res2.getColumnIndex("buyAmount")));
Log.d("NEWROW", "Adding data from row " + String.valueOf(res2.getPosition()));
SendUserData.add(current_user_data);
}
res2.close();
db.close();
Log.d("EXTRACTED", "The number of rows from which data was extracted was " + String.valueOf(SendUserData.size()));
return SendUserData;
}
If after running you check the log you should see :-
A line detailing how many rows were extracted from the table
A line for each row (if any were extracted) saying Adding data from row ? (where ? will be the row 0 being the first)
A line saying The number of rows from which data was extracted was ? (? will be the number of elements in the array to be returned)

one query for two purposes

I have the following two queries:
A.
db.query(DBHelper.TABLE, new String[] {
DBHelper._ID, DBHelper._DATE_AND_TIME,
DBHelper._SOURCE, DBHelper._MODE,
"SUM(" + DBHelper._AMOUNT + ")" },
DBHelper._DATE_AND_TIME + " BETWEEN ? AND ?",
new String[] { date_min, date_max }, null, null, null, null);
and result of sum goes to textview like this
String.valueOf(cursor.getString(4)).
Second query B.
db.query(DBHelper.TABLE, new String[] {
DBHelper._ID, DBHelper._DATE_AND_TIME,
DBHelper._SOURCE, DBHelper._MODE,
DBHelper._AMOUNT }, DBHelper._DATE_AND_TIME
+ " BETWEEN ? AND ?", new String[] { date_min, date_max },
null, null, null, null);
and result goes to
adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, from,
to, FLAG_AUTO_REQUERY);
What I want is to combine both queries. Close cursor after first query and to use same query (A) for adapter. So far I have added DBHelper._AMOUNT to SELECT of A query but ListView shows only the last entry result (not the whole data). How can I modify query A for showing SUM in TextView and then use same query for adapter.
In a normal query (like B), the database returns a result record for each table record that matches the WHERE filter.
However, when you are using an aggregate function like SUM(), the database computes a single value from all table records (or from all records in a group if you're using GROUP BY) and returns that as a single result record.
Therefore, your two queries are fundamentally different and cannot be combined into a single query.
(Please note that the first four result columns of your query A do not have any meaningful value because the result record is not guaranteed to correspond to any particular record in the original table; you should ask only for the SUM value.)

How to show 2 database values in ListView?

I have 2 activities(Novamensagem & Mensagenssalva) in Novamensagem.java I have a spinner with contacts values, a EditText and a Save button. I select a contact and write a text and hit save. The TEXT gets saved, and when i open Mensagenssalva.java all the TEXTs i write and save is there in a ListView. So i want to know how to the ListView show the name of the contact i selected in the Spinner and then show the message. eg:
Person's name
Message i have written.
//EDIT//
now the error is: Force to Close the app when i compile it. The code now:
ListView user = (ListView) findViewById(R.id.lvShowContatos);
//String = simple value ||| String[] = multiple values/columns
String[] campos = new String[] {"nome", "telefone"};
list = new ArrayList<String>();
c = db.query( "contatos", campos, null, null, null, null, null);
c.moveToFirst();
if(c.getCount() > 0) {
while(true) {
list.add(c.getString(c.getColumnIndex("nome")).toString());
list.add(c.getString(c.getColumnIndex("telefone")).toString());
if(!c.moveToNext()) break;
}
}
// the XML defined views which the data will be bound to
int[] to = new int[] { R.id.nome_entry, R.id.telefone_entry };
SimpleCursorAdapter myAdap = new SimpleCursorAdapter(this, R.layout.listview, c , campos, to, 0);
user.setAdapter(myAdap);
The LogCat errors:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.mensagem/com.example.mensagem.Contato}: java.lang.IllegalArgumentException: column '_id' does not exist
So the thing is, its trying to pull a "_id" from my database, but i dont have a "_id" column/row in it.
Posted from comments
You will have more control over your app while writing less lines of code by using a SimpleCursorAdapter as we discussed.
In order to use any CursorAdapter, your table must have a _id INTEGER PRIMARY KEY column, which you don't have. While I still recommend altering your table to add this column, there is a quick fix. If you don't specify a primary key all SQLite tables create an integer primary key by default, you can reference it with rowid, oid or _rowid_. But Android requires that the integer primary key column is named _id... Simply create an alias with the keyword AS for the meantime:
String[] campos = new String[] {"rowid as _id", "nome", "telefone"};
You need to create customAdapter instead of ArrayAdapter. Check out this link http://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/

Android SQLite Repeated Elements

I have an issue with SQLite on android. Right now, I'm pulling a JSON object from a server, parsing it, and putting each sub-object in a Table with things such as the Name, Row_ID, unique ID, etc. using this code:
public void fillTable(Object[] detailedList){
for(int i=0;i<detailedList.length;++i){
Log.w("MyApp", "Creating Entry: " + Integer.toString(i));
String[] article = (String[]) detailedList[i];
createEntry(article[0], article[1], article[2], article[3], article[4], article[5]);
}
}
createEntry does what it sounds like. It takes 6 strings, and uses cv.put to make an entry. No problems.
When I try to order them however, via:
public String[] getAllTitles(int m){
Log.w("MyApp", "getTitle1");
String[] columns = new String[]{KEY_ROWID, KEY_URLID, KEY_URL, KEY_TITLE, KEY_TIME, KEY_TAGS, KEY_STATE};
Log.w("MyApp", "getTitle2");
Cursor c = ourDatabase.query(DATABASE_TABLENAME, columns, null, null, null, null, KEY_TIME);
Log.w("MyApp", "getTitle3");
String title[] = new String[m];
Log.w("MyApp", "getTitle4");
int i = 0;
int rowTitle = c.getColumnIndex(KEY_TITLE);
Log.w("MyApp", "getTitle5");
for(c.moveToFirst();i<m;c.moveToNext()){
title[i++] = c.getString(rowTitle);
Log.w("MyApp", "getTitle " + Integer.toString(i));
}
return title;
}
Each entry actually has many duplicates. I'm assuming as many duplicates as times I have synced. Is there any way to manually call the onUpgrade method, which drops the table and creates a new one, or a better way to clear out duplicates?
Secondary question, is there any way to order by reverse? I'm ordering by time now, and the oldest added entries are first (smallest number). Is there a reverse to that?
If you don't want duplicates in one column then create that column with the UNIQUE keyword. Your database will then check that you don't insert duplicates and you can even specify what should happen in that case. I guess this would be good for you:
CREATE TABLE mytable (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
theone TEXT UNIQUE ON CONFLICT REPLACE
)
If you insert something into that table that already exists it will delete the row that already has that item and inserts your new row then. That also means that the replaced row gets a new _id (because _id is set to automatically grow - you must not insert that id yourself or it will not work)
Your second question: you can specify the direction of the order of if you append ASC (ascending) or DESC (descending). You want DESC probably.
Cursor c = ourDatabase.query(DATABASE_TABLENAME, columns, null, null, null, null, KEY_TIME + " DESC");

Populate a list from a database in Android

I’m trying to query a single table database that I’ve created in my code. To the best of my knowledge the database is being created correctly. The query is supposed to be used to populate a ListView but when I try to use the resulting cursor from my query to create SimpleCursorAdapter, it crashes with: java.lang.IllegalArgumentException: column '_id' does not exist. I am assuming this can be traced to the cursor, and also the cursor seems to be empty.
The database is created in the following way within the onCreate() of my implementation of a SQLiteOpenHelper:
db.execSQL("CREATE TABLE " + TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, title TEXT NOT NULL, path TEXT NOT NULL);");
And then the actual query is set up and executed in my DataHelper Class which is used to interact with the database:
public Cursor selectEntryStartsWith(String partialName , String title)
{
String where = "name LIKE '" + partialName + "%' AND title LIKE '" + title + "'";
if (title== null || title.equals("")){
where = "name LIKE '" + partialName + "%'";
}
Cursor cur = mDatabase.query(TABLE_NAME, new String[] {"_id", "name", "title"}, where, null, null, null, "name");
return cur;
}
The code that uses the cursor is as follows:
Cursor cursor = mDataHelper.selectEntryStartsWith("ex", null); //get all entries that start with "ex"
String [] from = new String [] { "name", "title" };
int [] to = new int [] { R.id.name, R.id.title };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(mContext, R.layout.listview_entry, cursor, from, to);
songList.setAdapter(adapter);
I'm using tabs to this last piece of code is from within the onActivityCreated() of a Fragment; I not that it might be better to extend a ListFragment, but I don't think this is the problem here in particularity.
Sorry in advance if I have missed an information that you may require, I've been banging my head on this problem for some time now.
Do you know the data is actually in the database? Run 'adb shell', cd to your data directory '/data/data/[app package name]/databases'. Then run sqlite3 [db file name]. Run some direct sql queries and make sure data exists.
If there is data there, rather than going right to the SimpleCursorAdapter, run some text queries in code, and see if you can access the results.
Once all of that works out, add the ListView stuff as a last step.
Some things to mention. If the user is typing in query values, you need to escape those statement values. Either use selectionArgs in the query statement:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String)
or use my stripped-down apache commons-lang, and the StringEscapeUtils class.
http://www.touchlab.co/blog/android-mini-commons/
Another thing to consider, although if you're not having trouble, its probably not an issue. 'name' and 'title' might be tricky keywords in sql statements.
The problem was indeed the database was not set up properly, I tried another method of inserting the data i.e. using ContentValues and inserting directly into the database, as opposed to using the precompiled insert statement I was using before.
The insert method now looks like this:
public long insert(String name, String title)
{
ContentValues cv = new ContentValues();
cv.put("name", name);
cv.put("title", title);
return mDatabase.insert(TABLE_NAME, null, cv);
/* The old code was using this precompiled statement
mInsertStatement.bindString(1, name);
mInsertStatement.bindString(2, title);
return mInsertStatement.executeInsert();
*/
}

Categories

Resources