Modifying the data of SimpleCursorAdapter - android

I extended SimpleCursorAdapter according to my needs. I want to show two textviews in a row.
One of these textviews is filled by the cursor but for the other one I want to use an ArrayList. Let me give an example to clarify:
For the first field I use the data from cursor
String[] columns = new String[] { ContactsContract.PhoneLookup.DISPLAY_NAME };
int[] to = new int[] { R.id.toptext };
I want to use ArrayList for the second field so that they form the following listview
I don't know how I can set the second field. Any help would be appreciated.

I haven't tested it but you could use the _id column of your query to map your values to the list and later bind the data.
private HashMap<Long, String> items = new HashMap<Long, String>(); // this will map the ids from the cursor to the values in the ArrayList
//get the cursor Cursor cursor = the query and then map the values:
int tmp = 0;
while (mc.moveToNext()) {
items.put(mc.getLong(mc.getColumnIndex("_id")), extra.get(tmp)); //or replace _id with your ID column from the query
tmp++;
}
Then pass this HashMap to your custom adapter constructor:
private HashMap<Long, String> extraStuff;
public YourCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to, HashMap<Long, String> extraSutff) {
// stuff
this.extraStuff = extraStuff;
}
and bind the values in the bindView() method:
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView top = (TextView) view.findViewById(R.id.toptext);
top.setText(cursor.getString(cursor.getColumnIndex(THE_COLUMN_FOR_THE_FIRST_TEXTVIEW)));
TextView bottom = (TextView) view.findViewById(R.id.bottomtext);
bottom.setText(extraStuff.get(cursor.getLong(cursor.getColumnIndex(THE_ID_COLUMN_FROM_THE_QUERY))));
}
Note: I don't know how efficient this will be if you have many rows in the cursor.

Related

get row from a cursor based on the id that is a column

currently in my cursor that I recieve on method setupChangeReasons(Cursor cursor), I have a list of records that I get from the database, I have a variable "mChangeReasonId", if this variable is 0 nothing happens, but if it has another value what I need is to get all the data of the row of this record, all the records that I receive have an id, description, number, employee, etc. I need to get all that row if the id is equal to "mChangeReasonId".
How can I get that specific row from the cursor, when my variable "mChangeReasonId" has a value other than 0? I need store this data in different variables.
private void setupChangeReasons(Cursor cursor) {
final DetailsSpinnerView spChangeReason = (DetailsSpinnerView) getView().findViewById(R.id.changeReason);
SimpleCursorAdapter changeReasonAdapter = new SimpleCursorAdapter(getActivity(), R.layout.spinner_item_empty, cursor, new String[]{eHubDatabaseManager.AbsenceReason.COL_DESCRIPTION}, new int[]{android.R.id.text1}, 0);
NothingSelectedSpinnerAdapter nothingSelectedSpinnerAdapter = new NothingSelectedSpinnerAdapter(changeReasonAdapter, R.layout.spinner_item_empty, getActivity());
changeReasonAdapter.setDropDownViewResource(R.layout.spinner_item);
spChangeReason.setAdapter(nothingSelectedSpinnerAdapter);
AcbItemWrapper acbItemWrapper = new AcbItemWrapper(cursor);
//variable mChangeReasonId
final int spinnerPosition = mChangeReasonId == 0 ? 0 : acbItemWrapper.getPositionOfInt(mChangeReasonId, eHubDatabaseManager.AbsenceReason.COL_ID) + 1; //+1 to account for NothingSelected
spChangeReason.setSelection(spinnerPosition);
spChangeReason.setOnItemSelectedListener(getChangeReasonListener(spinnerPosition, spChangeReason));
}

Change listview text Android

I have a SQLite database that is converted into a listview and everything is working fine. But i am facing a problem now:
I have a column named stage in my database. Stage will contain one of these integers: 0, 1 or 2. In the layout file of the listview items i have a textview called status, and the value of stage is printed into this textview. But i don't want 0, 1 or 2 printed in the textview, i want to replace the integer with a word.
So for example if the value of stage is 0, i want the content of status to be "hello". And if the value of stage is 1, i want the content of status to be "goodmorning". I have tried multiple things but i don't get it working.
The code of the listview:
private DBManager dbManager;
private ListView listView;
private SimpleCursorAdapter adapter;
final String[] from = new String[] { DatabaseHelper._ID,
DatabaseHelper.IDEA, DatabaseHelper.DESC, DatabaseHelper.STAGE};
final int[] to = new int[] { R.id.id, R.id.idea, R.id.desc, R.id.status };
dbManager = new DBManager(this);
dbManager.open();
Cursor cursor = dbManager.fetch();
listView = (ListView) findViewById(R.id.list_view);
listView.setEmptyView(findViewById(R.id.empty));
adapter = new SimpleCursorAdapter(this, R.layout.activity_view_record, cursor, from, to, 0);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
I hope somebody can help me, thanks in advance :).
You could implement a custom adapter rather than using SimpleCursorAdapter and then change/convert the value in the getView or bindView method within the adapter.
Alternately you could change/convert the values via the query that returns the cursor. Along the lines of :-
SELECT col1, col2, (CASE WHEN colx = 0 THEN 'Hello' ELSE 'GoodMorning' END) AS mynewcolum FROM TABLE;
Where col1, col2 and colx are existing columns and colx is the column that is to be converted.
Try like this
Take
int i;
Then check
if (i==0) {
textview.setTe xt("hello");
} else if (i==1) {
textview.setText("good morning");
}

How to position (select) a spinner on specific item by id with simplecursoradapter?

I'm populating a spinner with a number of records from my SQlite database using the following code:
DBHelper db = new DBHelper(getBaseContext());
Cursor cursor_clients = db.select("clients", "_id, name", "ORDER BY name"); // table, fields, filter/order
String[] columns = new String[] { "name" };
int[] to = new int[] { android.R.id.text1 };
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, cursor_clients, columns, to, 0);
mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner spnClients = (Spinner) findViewById(R.id.spnClients);
spnClients.setAdapter(mAdapter);
It works great, and I can use
spnAcademias.getSelectedItemId();
To get the _id of the selected record. My problem is: How to select an item on this spinner by the _id?
I have the _id of the row I want, I want it to show this row selected, and not the first row coming from the query.
Doing more research I ended up with the solution here: setSelection on Spinner based on rowId
I thought maybe there was a native solution without a loop, but there is not.
Solution:
public void setSpinnerItemById(Spinner spinner, int _id)
{
int spinnerCount = spinner.getCount();
for (int i = 0; i < spinnerCount; i++)
{
Cursor value = (Cursor) spinner.getItemAtPosition(i);
long id = value.getLong(value.getColumnIndex("_id"));
if (id == _id)
{
spinner.setSelection(i);
break;
}
}
}
If you're able to just as easily get the text value of the row you are looking for, then try the solution here, and more specifically the top comment on it: Set selected item of spinner programmatically
Use the following: spinnerObject.setSelection(INDEX_OF_CATEGORY2).
...
... I also found a way of getting the index without needing to loop through the adapter. I used the following mySpinner.setSelection(arrayAdapter.getPosition("Category 2"));

Is there a better way of handling this list of strings?

I am developing an app for Android
I have different categories:
String[] cat = { "Category", "Books", "Clothing", "Shoes", "Hobbies",
"General", "Electronics", "Transportation", "Medicine",
"Sports", "Education", "Outdoor"};
The UI asks the user to select a category, Name, and some description which is then written to a db. When the user presses the List button, every category that is filled is shown and the items under that category is also show using an ExpandableListActivity.
List<List<String>> children = new ArrayList<List<String>>();
/**********************
I have a list for each category!!! But I don't like this solution. :(
**********************/
List<String> books = new ArrayList<String>();
List<String> clothing = new ArrayList<String>();
...
...
public void fillData() {
// Get all of the notes from the database and create the item list
Cursor c = mDbHelper.fetchAllItems();
startManagingCursor(c);
// for all rows
for(int i=0; i<c.getCount(); i++)
{
// next row
c.moveToNext();
// pick a category
String t = c.getString(c.getColumnIndex("category"));
switch (getCat(t))
{
case Books:
books.add(c.getString(c.getColumnIndex("name")));
break;
case Clothing:
// do stuff for Clothing
break;
/**
And there are other cases for the rest of the categories but i am not listing
them here, since it is the same process
*/
default:
break;
} // end switch
} // end for loop
//for each category that has been filled up
children.add(category);
} // end function
My Question:
is it possible to not have to create a list for each category? I tried with one list but the results do not look very good. All categories show the same items and not the individual items, which makes sense.
You do not need to create the lists yourself.
You may want to have 2 tables - one listing the categories names and their ids (which will be primary table key) another one listing the stuff where each row has an item's category id, an item name and whatever else for a single item.
Then you can have SimpleCursorTreeAdapter like this:
SimpleCursorTreeAdapter (Context context, Cursor cursor, int groupLayout, String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom, int[] childTo).
For groupLayout you will have android.R.layout.simple_expandable_list_item_1. For childLayout you will have android.R.layout.simple_list_item_1
For groupFrom you will have
String[] groupFrom = { FLD_CATEGORY_NAME };
int[] groupTo = { android.R.id.text1 };
For childFrom you will have
String[] childFrom = { FLD_ITEM_NAME };
int[] childTo = { android.R.id.text1 };
or rather your own layout if you want to display more than 1 or 2 elements
And you will have
protected Cursor getChildrenCursor(Cursor groupCursor) {
int categoryId = groupCursor.getColumnIndex(FLD_CATEGORY_ID);
// and here you a Cursor from your items table WHERE CTAEGORY_ID == categoryId
}
i just created a list of lists, and worked :)

How to insert extra elements into a SimpleCursorAdapter or Cursor for a Spinner?

I have a Spinner which is to show a list of data fetched from database. The data is returned to a cursor from query, and the cursor gets passed to spinner's SimpleCursorAdapter. It is working fine as such, but I want to insert another item on top of this data. For example, the spinner is already showing a list of user created templates saved in DB, but I want to insert "New Template" and "Empty Template" on top of the list of templates, and it needs to be inserted into Cursor/SimpleCursorAdapter somehow.
I have considered using an arraylist and populating the arraylist from cursor, but cursor is better solution for me since it contains other related rows of data too. I searched internet for other solutions and found some answers asking to use CursorWrapper for this purpose, but I could not find a concrete example how to use CursorWrapper to accomplish what I want. How can I insert some rows in cursor or can someone please give a easy to follow CursorWrapper example!! Thanks in advance.
You can use a combination of MergeCursor and MatrixCursor with your DB cursor like this:
MatrixCursor extras = new MatrixCursor(new String[] { "_id", "title" });
extras.addRow(new String[] { "-1", "New Template" });
extras.addRow(new String[] { "-2", "Empty Template" });
Cursor[] cursors = { extras, cursor };
Cursor extendedCursor = new MergeCursor(cursors);
This is the method I tried.
MatrixCursor m = new MatrixCursor(c.getColumnNames());
Cursor c = DBHelper.rawQuery("Select values from your_table");
MatrixCursor m = new MatrixCursor(c.getColumnNames());
//Use MatrixCursor#addRow here to add before the original cursor
while (c.moveToNext()) {
//Use MatrixCursor#addRow here to add before the original row
DBHelper.insertRow(c, m);
//Use MatrixCursor#addRow here to add after the original row
}
//Use MatrixCursor#addRow here to add after the original cursor
m.addRow(new String[]{col1Val, col2Val, col3Val,..., //to match the number of columns needed});
DBHelper.insertRow()
public final static void insertRow(Cursor from, MatrixCursor to) {
final String columns[] = from.getColumnNames(), values[] = new String[columns.length];
final int size = columns.length;
for (int i = 0; i < size; i++) {
values[i] = getStringFromColumn(from, columns[i]);
}
to.addRow(values);
}
With this method, you can add any amount of rows anywhere in your cursor. Even though it is not making use of CursorWrapper, it can be used with CursorAdapters or SimpleCursorAdapters.
I tried the solution provided by #naktinis, but the result wasn't what I expected. What I myself wanted to achieve as an adapter in which new elements can be added at the top (index 0). However, with the solution given, new elements were indeed added at the top but only to the END of the MatrixCursor. In other words, when I added rows dynamically to the "extras" MatrixCursor, I got something like this:
"extras" row 1
"extras" row 2
"extras" row 3
"cursor" row 1
"cursor" row 2
"cursor" row 3.
However, what I really wanted to achieve was something like this:
"extras" row 3
"extras" row 2
"extras" row 1
"cursor" row 1
"cursor" row 2
"cursor" row 3.
In other words, most recent elements enter at the top (index 0).
I was able to achieve this manually by doing the follow. Note that I did not include any logic to handle dynamically removing elements from the adapter.
private class CollectionAdapter extends ArrayAdapter<String> {
/**
* This is the position which getItem uses to decide whether to fetch data from the
* DB cursor or directly from the Adapter's underlying array. Specifically, any item
* at a position lower than this offset has been added to the top of the adapter
* dynamically.
*/
private int mCursorOffset;
/**
* This is a SQLite cursor returned by a call to db.query(...).
*/
private Cursor mCursor;
/**
* This stores the initial result returned by cursor.getCount().
*/
private int mCachedCursorCount;
public Adapter(Context context, Cursor cursor) {
super(context, R.layout.collection_item);
mCursor = cursor;
mCursorOffset = 0;
mCachedCursorCount = -1;
}
public void add(String item) {
insert(item, 0);
mCursorOffset = mCursorOffset + 1;
notifyDataSetChanged();
}
#Override
public String getItem(int position) {
// return the item directly from underlying array if it was added dynamically.
if (position < mCursorOffset) {
return super.getItem(position);
}
// try to load a row from the cursor.
if (!mCursor.moveToPosition(position - mCursorOffset)) {
Log.d(TAG, "Failed to move cursor to position " + (position - mCursorOffset));
return null; // this shouldn't happen.
}
return mCursor.getString(INDEX_COLLECTION_DATA);
}
#Override
public int getCount() {
if (mCachedCursorCount == -1) {
mCachedCursorCount = mCursor.getCount();
}
return mCursorOffset + mCachedCursorCount;
}
}

Categories

Resources