I have database table with the columns {Name, Time (UTC format) , Latitude, Longitude}
I display the table using a ListActivity with a SimpleCursorAdapter.
I would like that the column Time show the time in a human readable format (13-07-2010 10:40) rather than in UTC format (18190109089).
How can I specify that the values from column Time need some filtering/adaptation?
POSSIBLE SOLUTION (with a problem):
SimpleCursorAdapter offers the method:
setCursorToStringConverter(SimpleCursorAdapter.CursorToStringConverter cursorToStringConverter);
to specify how a class that is able to convert a Cursor to CharSequence (convertToString(Cursor cursor).
Anyway I don't know in which format should be the return CharSequence paramater!
The simplest way to format a cursor value is to use SimpleCursorAdapter.setViewBinder(..):
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.list, cursor,
new String[] { Definition.Item.TITLE, Definition.Item.CREATE_DATE }, new int[] { R.id.title, R.id.createDate});
adapter.setViewBinder(new ViewBinder() {
public boolean setViewValue(View aView, Cursor aCursor, int aColumnIndex) {
if (aColumnIndex == 2) {
String createDate = aCursor.getString(aColumnIndex);
TextView textView = (TextView) aView;
textView.setText("Create date: " + MyFormatterHelper.formatDate(getApplicationContext(), createDate));
return true;
}
return false;
}
});
i also had the same problem after long struggle finally i found answer :) ( see below )
use setViewText (TextView v, String text)
for example
SimpleCursorAdapter shows = new SimpleCursorAdapter(this, R.layout.somelayout, accountCursor, from, to)
{
#Override
public void setViewText(TextView v, String text) {
super.setViewText(v, convText(v, text));
}
};
private String convText(TextView v, String text)
{
switch (v.getId())
{
case R.id.date:
String formatedText = text;
//do format
return formatedText;
}
return text;
}
You can use setViewBinder(), or subclass SimpleCursorAdapter and override bindView().
You can use SQLite syntax on that column to format the date.
Something like this will do it
SELECT strftime('%d-%m-%Y %H:%M',1092941466,'unixepoch');
SELECT strftime('%d-%m-%Y %H:%M',timecol,'unixepoch');
Going thru this old post, noticed I have done something similar that might help:
public class FormatCursorAdapter extends SimpleCursorAdapter {
protected int[] mFormats;
public static final int FORMAT_TEXT=0;
public static final int FORMAT_CURRENCY=1;
public static final int FORMAT_DATE=2;
public FormatCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int[] formats, int flags) {
super(context, layout, c, from, to, flags);
mFormats = formats;
ViewBinder viewBinder = new ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
int formatType = mFormats[columnIndex-1];
switch (formatType) {
case FORMAT_CURRENCY:
NumberFormat nf = NumberFormat.getCurrencyInstance();
nf.setMaximumFractionDigits(2);
((TextView)view).setText(nf.format(cursor.getDouble(columnIndex)));
return true;
case FORMAT_DATE:
DateFormat df = SimpleDateFormat.getDateTimeInstance();
((TextView)view).setText(df.format(new Date(cursor.getLong(columnIndex))));
return true;
}
return false;
}
};
setViewBinder(viewBinder);
}
}
Usage:
// For the cursor adapter, specify which columns go into which views with which format
String[] fromColumns = {
Table.COLUMN_TITLE,
Table.COLUMN_AMOUNT,
Table.COLUMN_DATE};
int[] toViews = {
R.id.tvTitle,
R.id.tvAmount,
R.id.tvDate};
int[] formatViews = {
FormatCursorAdapter.FORMAT_TEXT,
FormatCursorAdapter.FORMAT_CURRENCY,
FormatCursorAdapter.FORMAT_DATE};
mAdapter=new FormatCursorAdapter(getContext(),R.layout.item_operation,cursor,
fromOpsColumns,toOpsViews,formatViews,0);
mListView.setAdapter(mOpsAdapter);
Hope this helps anyone out there !
Related
MAIN QUESTION:
Wondering if there's any conflict with the two spinners when I try display the results with my LoadGrid. Like if one is overriding the other and ending up with an empty result because of it. If so how do I go about combining the two results from the spinners to get the desired view.
SOME DETAILS:
I want to use two spinners on my gridview to act as filters. One for TERMS and one for STATUS. Specifically what I want to happen is that the user can use those two spinners INDIVIDUALLY or TOGETHER to filter the view of accounts in the DB.
Taking it one step at a time I've gotten one spinner running and working properly. So I cloned that working spinner code to get my second one up and running. Nope, not working. Using either of the two spinners now result in nothing. No accounts show up anymore. It'll let me select from the spinners but my grid will still be empty.
If anything is missing or you need to see more of the code please feel free to ask. Cheers.
Here's the spinners snippets:
Utilities.ManageTermSpinner(this.getParent(), spinTerm);
try {
spinTerm.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
LoadGrid();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
} catch (Exception ex) {
txtTest.setText(ex.toString());
}
Utilities.ManageStatSpinner(this.getParent(), spinStat);
try {
spinStat.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
LoadGrid();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
} catch (Exception ex) {
txtTest2.setText(ex.toString());
}
}
Here's the LoadGrid that it references:
public void LoadGrid() {
dbHelper = new DatabaseHelper(this);
try {
View v = spinTerm.getSelectedView();
TextView txt = (TextView) v.findViewById(R.id.txtTermClass);
String Terms = String.valueOf(txt.getText());
Cursor c = dbHelper.getAccByTerms(Terms);
startManagingCursor(c);
View x = spinStat.getSelectedView();
TextView txt2 = (TextView) x.findViewById(R.id.txtStatID);
String Status = String.valueOf(txt2.getText());
Cursor b = dbHelper.getAccByStatus(Status);
startManagingCursor(b);
String[] from = new String[]{DatabaseHelper.colName, DatabaseHelper.colAmount, DatabaseHelper.colTermsClass, DatabaseHelper.colStatClass};
int[] to = new int[]{R.id.colName, R.id.colAmount, R.id.colTerms, R.id.colStat};
SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.gridrow, c, from, to);
grid.setAdapter(sca);
SimpleCursorAdapter sba = new SimpleCursorAdapter(this, R.layout.gridrow, b, from, to);
grid.setAdapter(sba);
} catch (Exception ex) {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setMessage(ex.toString());
b.show();
}
}
The dbHelper snippets for TERMS and STATUS:
public Cursor getAccByTerms(String Terms)
{
SQLiteDatabase db=this.getReadableDatabase();
String [] columns=new String[]{"_id",colName,colAmount,colPurpose,colTermsClass,colDate,colEditDate,colStatClass};
Cursor c=db.query(viewAccs, columns, colTermsClass+"=?", new String[]{Terms}, null, null, null);
return c;
}
public Cursor getAccByStatus(String Status)
{
SQLiteDatabase db=this.getReadableDatabase();
String [] columns=new String[]{"_id",colName,colAmount,colPurpose, colTermsClass,colDate,colEditDate,colStatClass};
Cursor d=db.query(viewAccs,columns, colStatClass +"=?",new String[]{Status},null,null,null);
return d;
}
And the Utilities snippet where I keep the ManageSpinner stuff:
public class Utilities {
static public void ManageTermSpinner(Context context, Spinner view) {
DatabaseHelper dbHelper = new DatabaseHelper(context);
Cursor c = dbHelper.getAllTerms();
SimpleCursorAdapter ca = new SimpleCursorAdapter(context, R.layout.termspinnerrow, c, new String[]{DatabaseHelper.colTermsClass, "_id"}, new int[]{R.id.txtTermClass});
view.setAdapter(ca);
}
static public void ManageStatSpinner(Context context, Spinner view) {
DatabaseHelper dbHelper = new DatabaseHelper(context);
Cursor d = dbHelper.getAllStatus();
SimpleCursorAdapter da = new SimpleCursorAdapter(context,R.layout.statspinnerrow, d, new String[]{DatabaseHelper.colStatClass,"_id"}, new int[]{R.id.txtStatClass});
view.setAdapter(da);
}
This is how you need to do it:
public Cursor getAccByTermsAndStatus(String Terms, String status)
{
SQLiteDatabase db=this.getReadableDatabase();
String [] columns=new String[]{"_id",colName,colAmount,colPurpose,colTermsClass,colDate,colEditDate,colStatClass};
Cursor c=db.query(viewAccs, columns, colTermsClass+"=? AND " + colStatClass + "=?", new String[]{Terms, status}, null, null, null);
return c;
}
I'm a little bit stuck on viewbinders in android
here's my code:
public void displayAllAlerts() {
Cursor mCursor = mDbAdapter.fetchAllAlerts();
//Bind Columns
String[] columns = new String[] {
DbAdapter.KEY_ID,
DbAdapter.KEY_PLACE,
DbAdapter.KEY_LONG,
DbAdapter.KEY_LAT,
DbAdapter.KEY_STATUS
};
int[] to = new int[] {
R.id.txtId,
R.id.txtPlace,
R.id.txtLong,
R.id.txtLat,
R.id.tglBtnAlert
};
mSimpleCursorAdapter = new SimpleCursorAdapter(
this,
R.layout.layout_lvrow,
mCursor,
columns,
to,
0);
ListView lvAlerts = (ListView) findViewById(R.id.lvAlerts);
lvAlerts.setAdapter(mSimpleCursorAdapter);
}
The problem is that 'DbAdapter.key_status' is formatted as an int in my database, but someway I have to change it to a boolean, beacuase it's my status for my togglebutton.
I know i have to use .setViewBinder, but i have no idea were to start.
I tried the following from some tutorials but it does not work:
mSimplecursorAdapter.setViewBinder(new ViewBinder() {
public boolean setViewValue(View aView, Cursor aCursor, int aColumnIndex) {
if (aColumnIndex == 5) {
String strBool = aCursor.getString(aColumnIndex);
ToggleButton tb = (Togglebutton) aView;
if (strBool=="0") {
tb.setChecked = false;
}else{
tb.setChecked = true;
}
return true;
}
return false;
}
thanks in advance
(also tried already to use developer site of android but it's giving me a real headache)
The code does not work because you must use String.equals() or TextUtils.equals() to compare strings.
To handle boolean columns on SQLite, I usually handle this data as INTEGER with values 1 or 0:
public boolean setViewValue(View aView, Cursor aCursor, int aColumnIndex) {
if (aColumnIndex == 5) {
boolean checked = aCursor.getInt(aColumnIndex) == 1;
ToggleButton tb = (Togglebutton) aView;
tb.setChecked(checked);
return true;
}
return false;
}
Im trying to change text color in a listview, which is displaying my entries from database. The problem is that it displays invisible text ( or it displays nothing at all. only the lines which are separating my entries on this list) but after clicking on entry it shows me details from this entries. Displaying works good without trying to use ViewBinder.
// map each name to a TextView
String[] from = new String[] { "event" };
int[] to = new int[] { R.id.countryTextView };
conAdapter = new SimpleCursorAdapter(Clock.this, R.layout.day_plan, null, from, to);
SimpleCursorAdapter.ViewBinder binder = new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex){
int getIndex = cursor.getColumnIndex("colour");
String empname = cursor.getString(getIndex);
tv = (TextView)findViewById(R.id.countryTextView);
tv.setTextColor(Color.WHITE);
if(empname.equals("Green"))
{
tv.setTextColor(Color.WHITE);
return true;
}
return false;
}
};
setListAdapter(conAdapter); // set adapter
((SimpleCursorAdapter) conAdapter).setViewBinder(binder);
How can I change it to work ok ?
You have to add the text to the textview:
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex)
{
((TextView) view).setTextColor(Colors.RED);
((TextView) view).setText(cursor.getString(cursor.getColumnIndex("YOUR-COLUMN-NAME")));
return false;
}
change line
tv = (TextView)view.findViewById(R.id.countryTextView); // <-- add 'view.'
call
conAdapter.setViewBinder(SimpleCursorAdapter.ViewBinder)
setListAdapter(conAdapter); // set adapter
Well, I have read almost 50 links related to this question, but my code still not working.
I have a Custom adapter which extends SimpleCursorAdapter class, and I use that adapter to fill the ListView on onCreate method
private void populateListView()
{
String[] from = new String[] { SchemaHelper.TASK_DESCRIPTION, SchemaHelper.TASK_CREATED_ON, SchemaHelper.TASK_ID };
int[] to = new int[] {R.id.lv_row_description, R.id.lv_row_created_on};
tasksCursor = schemaHelper.getTasks();
startManagingCursor(tasksCursor);
tasksAdapter = new TasksAdapter(this, R.layout.tasks_listview_row, tasksCursor, from, to);
setListAdapter(tasksAdapter);
}
The App is a simple task manager, I want to update the ListView contents when the user submits a new task without calling setListAdapter() again.
I have tried notifyDataSetChanged (running on ui thread), invalidate, requery(deprecated)... almost everything.
I'm doing something wrong?
EDIT:
This is the method where I add a new task to the database
private void addTask(String description)
{
String message = "";
schemaHelper.open();
if(schemaHelper.isAlreadyInDatabase(description))
{
message = getString(R.string.task_already_exists);
}
else
{
message = getString(R.string.task_succesfully_added);
schemaHelper.insertTask(description);
populateListView();
newTask.setText("");
}
schemaHelper.close();
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
ADAPTER CLASS:
private class TasksAdapter extends SimpleCursorAdapter
{
private LayoutInflater layoutInflater;
private Cursor cursor;
public TasksAdapter(Context context, int layout, Cursor c, String[] from, int[] to)
{
super(context, layout, c, from, to);
cursor = c;
cursor.moveToFirst();
layoutInflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if(cursor.getPosition() < 0)
{
cursor.moveToFirst();
}
else
{
cursor.moveToPosition(position); // Here throws the error
}
View row = layoutInflater.inflate(R.layout.tasks_listview_row, null);
TextView description = (TextView) row.findViewById(R.id.lv_row_description);
TextView createdOn = (TextView) row.findViewById(R.id.lv_row_created_on);
description.setText(cursor.getString(cursor.getColumnIndexOrThrow(SchemaHelper.TASK_DESCRIPTION)));
createdOn.setText(getString(R.string.added_on) + " " + TaskHelper.formatDateWithSuffix(cursor.getString(cursor.getColumnIndexOrThrow(SchemaHelper.TASK_CREATED_ON))));
return row;
}
}
i dont know much of the taskCursor and taskAdapter but i used ArrayAdapter i guess, well have a look in my code and take your own conclusions.
//LISTVIEW database CONTATO
ListView user = (ListView) findViewById(R.id.lvShowContatos);
//String = simple value ||| String[] = multiple values/columns
String[] campos = new String[] {"nome", "telefone"};
list = new ArrayList<String>();
Cursor c = db.query( "contatos", campos, null, null, null, null, "nome" + " ASC ");
c.moveToFirst();
String lista = "";
if(c.getCount() > 0) {
while(true) {
list.add(c.getString(c.getColumnIndex("nome")).toString());
if(!c.moveToNext()) break;
}
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, list);
user.setAdapter(adapter);
If you don't want to use requery() you can simply pass a new Cursor with the same query:
tasksCursor.close();
tasksCursor = schemaHelper.getTasks();
startManagingCursor(tasksCursor);
tasksAdapter.changeCursor(tasksCursor);
I assume that when you call addTask() you have already called populateListView() once. Try changing addTask() to this:
private void addTask(String description)
{
String message = "";
schemaHelper.open();
if(schemaHelper.isAlreadyInDatabase(description))
{
message = getString(R.string.task_already_exists);
}
else
{
message = getString(R.string.task_succesfully_added);
schemaHelper.insertTask(description);
// Remove call to populateListView(), just update the Cursor
tasksCursor.close();
tasksCursor = schemaHelper.getTasks();
startManagingCursor(tasksCursor);
tasksAdapter.changeCursor(tasksCursor);
newTask.setText("");
}
schemaHelper.close();
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
If this "doesn't work", please be more specific. Is it throwing an error, if so what kind?
You are doing a little too much work in your adapter. Please watch Android's Romain Guy at Google Talks discuss adapters and getView(). However since you only want to pass one special string to your createdOn TextView, let's do something very different and override setViewText():
Try this:
public class TasksAdapter extends SimpleCursorAdapter {
String prefix;
public TasksAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to) {
super(context, layout, cursor, from, to);
// This is constant so set it once and consider adding the space to the end of the String in strings.xml
prefix = getString(R.string.added_on) + " ";
}
#Override
public void setViewText(TextView v, String text) {
if(v.getId() == R.id.lv_row_created_on)
v.setText(prefix + TaskHelper.formatDateWithSuffix(text));
else
super.setViewText(v, text);
}
}
The rest of the data is taken care of with SimpleCursorAdapter's existing methods.
I have an android.R.layout.simple_list_item_multiple_choice with checkboxes an want so initiate some of them.
How can I do that?
I have the following code:
private void fillList() {
Cursor NotesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(NotesCursor);
String[] from = new String[] { NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_BODY, NotesDbAdapter.KEY_CHECKED };
int[] to = new int[] {
android.R.id.text1,
android.R.id.text2,
//How set checked or not checked?
};
SimpleCursorAdapter notes = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_multiple_choice, NotesCursor,
from, to);
setListAdapter(notes);
}
Put the resource id of your checkbox in your row layout into the to array, corresponding to the NotesDbAdapter.KEY_CHECKED cursor in from array.
Implement a SimpleCursorAdapter.ViewBinder.
Have the ViewBinder.setViewValue() method check for when its called for the NotesDbAdapter.KEY_CHECKED column.
When it is not the KEY_CHECKED column, have it return false the the adapter will do what it normally does.
When it is the KEY_CHECKED column, have it set the CheckBox view (cast required) to checked or not as you wish and then return trueso that adapter won't attempt to bind it itself. The cursor and corresponding column id is available to access query data to determine whether to check the checkbox or not.
Set your ViewBinder in your SimpleCursorAdapter via setViewBinder()
Here's one of my ViewBinder implementations. Its not for checboxes, rather its for doing some fancy formatting of a text view, but it should give you some idea for the approach:
private final SimpleCursorAdapter.ViewBinder mViewBinder =
new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(
final View view,
final Cursor cursor,
final int columnIndex) {
final int latitudeColumnIndex =
cursor.getColumnIndexOrThrow(
LocationDbAdapter.KEY_LATITUDE);
final int addressStreet1ColumnIndex =
cursor.getColumnIndexOrThrow(
LocationDbAdapter.KEY_ADDRESS_STREET1);
if (columnIndex == latitudeColumnIndex) {
final String text = formatCoordinates(cursor);
((TextView) view).setText(text);
return true;
} else if (columnIndex == addressStreet1ColumnIndex) {
final String text = formatAddress(cursor);
((TextView) view).setText(text);
return true;
}
return false;
}
};