SimpleCursorAdapter to[] and from[] mapping with a content provider - android

I have a ListView with 5 TextViews and so I am using a SimpleCursorAdapter to populate it. The data's coming from a content provider.
My problem is the with the _id column. I know I have to include it for the adapter to work. My problem is, I have 5 text views and I'll set the projection array for six columns.
Arrays of to[] and from[]
static {
from = new String[] {
EmployeeProviderContract.ROW_ID,
EmployeeProviderContract.F_NAME,
EmployeeProviderContract.L_NAME,
EmployeeProviderContract.ROW_EMP_ID,
EmployeeProviderContract.AGE,
EmployeeProviderContract.SEX
};
to = new int[] {
R.id.employee_first_name,
R.id.employee_last_name,
R.id.e_employee_id,
R.id.e_age,
R.id.e_sex
};
}
As you can see, I have 5 items in the to[] and 6 items in the from[] (because of the _id).
The simple cursor adapter
mAdapter = new SimpleCursorAdapter(getApplicationContext(),
R.layout.single_row_layout, // The row template
null, // Cursor but we dont have one right now, so NULL. Will come from swapCursor()
from,// Columns to show from
to, // The layout ids i.e individual text views to show the data in
0); // Default 0 as FLAG
So as a result, when the cursor returns, it sets the value of _id in the R.id.employee_first_name and so on with the rest of the values. I dont want to show the _id in the text views. I cant remove the _id otherwise it throws an exception. How do I fix this ? Very stupid problem but I can't seem to find a proper way.
This is what is content provider query looks like
Cursor returnCursor = db.query(EmployeeProviderContract.EMP_PERSONAL_TABLE_NAME,
projection, selection , selectionArgs, null, null, sortOrder);
Note: I am extending Activity and not ListActivity.

Maybe the Cursor returned from the ContentProvider does not include an "_id" column. Check if your database table has an _id column. The best practice is to implement the BaseColumns interface in the inner class(table class) inside your Contract class, which is used by your implementation of SQLiteOpenHelper to create the database..

Related

Android - populate ListView SQLite, cursor null pointer

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).

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/

How to add an item to SimpleCursorAdapter?

I have a simple database table with 2 columns "_id" and "title".
and I'm displaying the data in a spinner, and it works well.
but I need to add one more item at the top of the spinner list that is not from the database with id = 0 and title = "not specified";
Spinner list = (Spinner) findViewById(R.id.spinner);
Cursor cursor = database.getAll(); // returns cursor with objects
String[] columns = new String[] {"title"};
int[] to = new int[] {R.id.title};
list.setAdapter(new SimpleCursorAdapter(this, R.layout.object_item_simple, cursor, columns, to));
I need to know the selected item id from the database, i can do this with list.getSelectedItemId();
so I can't use ArrayAdapter instead of SimpleCursorAdapter, because i don't think that there is a method for setting the id for each item on the adapter.
is there a way to do this?
Thanks.
You could create an object out of your id and title and build a list of these objects with the cursor. Then insert your artificial entry at the top top of that list.
Then when you construct your Adapter pass in this list.
Alternatively you could put a dummy value into your database, although that would be weird and maybe not possible depending on your query and data. The ArrayAdapter is much more sensible
How to Do This With SimpleCursorAdapter
This method:
Is Efficient
Works with standard CursorLoader and SimpleCursorAdapter idioms
Great with ContentProvider data
I create the item i want to insert into the cursor as a static MatrixCursor
private static final MatrixCursor PLATFORM_HEADER_CURSOR = new MatrixCursor(
//These are the names of the columns in my other cursor
new String[]{
DataContract.ReflashPackage._ID,
DataContract.ReflashPackage.COLUMN_PLATFORM
});
static {
PLATFORM_HEADER_CURSOR.addRow(new String[]{
"0",
"Select a Platform")
});
}
Here is my implementation of onLoadFinished which merges the cursor and passes it to the adapter.
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch (loader.getId()) {
case PLATFORM_CURSOR_LOADER_ID:
Cursor mergedCursor = addPlatformHeaderToCursor(data);
mPlatformAdapter.swapCursor(mergedCursor);
break;
}
}
#NonNull
private static Cursor addPlatformHeaderToCursor(Cursor platforms) {
Cursor[] cursorToMerge = new Cursor[2];
cursorToMerge[0] = PLATFORM_HEADER_CURSOR;
cursorToMerge[1] = platforms;
return new MergeCursor(cursorToMerge);
}
One technique that I use often is I will define an object (such as EntryObject) that has the variables I am going to need from the cursor to display. Once I have this I can iterate through the cursor and place the information into those EntryObjects and place them in an ArrayList or an array.
Then you can build a customer ArrayAdapter that will work with your new object to pull as much data as you need and display it how you want to.

Retrieving and displaying a contact name from a contact id while using a SimpleCursorAdapter

I am storing information on the phone's contacts using a sqlite database.
The fields I am storing are: _id, contact_id, body where _id is the row's id, contact_id is the phone contact's id and body is just a simple text which is the actual information I am storing.
I'm using a SimpleCursorAdapter to map the data to the view, like so:
Cursor cursor = database.fetchInformation(); // fetch info from DB
String[] from = new String[] { CONTACT_ID, BODY };
int[] to = new int[] { R.id.contact, R.id.body };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to);
getListView().setAdapter(adapter);
What I would actually want is to get the contact name that is associated with this CONTACT_ID, and have that be shown in the view.
I can't seem to find a simple solution. I've tried implementing my own SimpleCursorAdapter and rewriting setViewText(TextView, String) but it didn't work. Also, it just seems overly complicated for such a simple task.
Any help? Thanks.
You really have two options here:
1) You could create a MatrixCursor that contains all the information you wish to bind to your ListView. While its not very difficult to do this, its probably not the most efficient use of memory because you would need to get the name of every contact in your cursor.
2) You could subclass from CursorAdapter. Its pretty simple to implement the appropriate newView and bindView methods. Inside of bindView you would simply query the phone's contact content provider to get the name of the contact currently being bound.
try this
String where=PEOPLE.CONTACT_ID+"="+requiredId;
String[] projection={People.Name};//u only need name right?
int[] to = new int[] {R.id.body };//if body is ur text view
Cursor cursor = getContentResolver().query(People.CONTENT_URI,projection,where,null, null);
ListAdapter adapter=new SimpleCursorAdapter(this,R.layout.row,result,projection,to);
setListAdapter(adapter);

Removing rows from an Android SQLite Cursor

I query and get a result set back, but I need to do some calculations that are impossible in the SQLite WHERE clause in order to determine what shows up in the ListView. How can I remove certain rows from the cursor? I know it is the same question as this Filter rows from Cursor so they don't show up in ListView but that answer does not help. Can an example be provided if there isn't a simpler way to do this?
It might work to simply retain all the rows in the Cursor, but then use a custom adapter to hide the unwanted rows at display time. For example, if you extend CursorAdapter, then you might have something like this in your bindView implementation:
View v = view.findViewById(R.id.my_list_entry);
boolean keepThisRow = .......; // do my calculations
v.setVisibility(keepThisRow ? View.VISIBLE : View.GONE);
There should be a better way to do this, but what I ended up doing is storing the ID of each row I wanted in a string ArrayList, and then requerying where _id IN arraListOfIds.toString(), replacing the square brackets with parentheses to fit SQL syntax.
// Get all of the rows from the database
mTasksCursor = mDbHelper.fetchAllTasks();
ArrayList<String> activeTaskIDs = new ArrayList<String>();
// calculate which ones belong
// .....
if (!hasCompleted)
activeTaskIDs.add(mTasksCursor.getString(TaskerDBadapter.INDEX_ID));
// requery on my list of IDs
mTasksCursor = mDbHelper.fetchActiveTasks(activeTaskIDs);
public Cursor fetchActiveTasks(ArrayList<String> activeTaskIDs)
{
String inClause = activeTaskIDs.toString();
inClause = inClause.replace('[', '(');
inClause = inClause.replace(']', ')');
Cursor mCursor = mDb.query(true, DATABASE_TABLE, columnStringArray(),
KEY_ROWID + " IN " + inClause,
null, null, null, null, null);
if (mCursor != null) { mCursor.moveToFirst(); }
return mCursor;
}
ContentResolver cr = getContentResolver();
Cursor groupCur = cr.query(
Groups.CONTENT_URI, // what table/content
new String [] {Groups._ID, Groups.NAME}, // what columns
"Groups.NAME NOT LIKE + 'System Group:%'", // where clause(s)
null, // ???
Groups.NAME + " ASC" // sort order
);
The "What Columns" piece above is where you can tell the cursor which rows to return. Using "null" returns them all.
I need to do some calculations that
are impossible in the SQLite WHERE
clause
I find this very hard to believe; my experience has been that SQL will let you query for just about anything you'd ever need (with the exception of heirarchical or recursive queries in SQLite's case). If there's some function you need that isn't supported, you can add it easily with sqlite_create_function() and use it in your app. Or perhaps a creative use of the SELECT clause can do what you are looking for.
Can you explain what these impossible calculations are?
EDIT: Nevermind, checking out this webpage reveals that the sqlite_create_function() adapter is all closed up by the Android SQLite wrapper. That's annoying.

Categories

Resources