I've created a subclass of CursorAdapter which is used to display 4 separate lists of data in my application.
Each list uses a different column from the database. My question is, how should I tell the adapter which column to use?
In the 2 brief examples below, which would be considered the better practice:
Option 1
Pass the column name to the constructor of my adapter.
This means the fragment will need to know the name of the column.
-
// In my fragment:
DBHelper helper = new DBHelper(getActivity());
Cursor cursor = helper.getTitleCursor();
adapter = new CustomCursorAdapter(getActivity(), cursor, DBHelper.COL_TITLE);
// The constructor of my CursorAdapter:
public CustomCursorAdapter(Context context, Cursor cursor, String colName) {
super(context, cursor, 0);
inflater = LayoutInflater.from(context);
this.displayColumn = colName;
}
// In my cursor adapter:
public void bindView(View view, Context context, Cursor cursor) {
TextView title = (TextView) view.findViewById(R.id.row_title);
String titleText = cursor.getString(cursor.getColumnIndex(displayColumn));
title.setText(titleText);
}
Option 2
When creating the cursor, use AS to give the column a specific name.
This means the fragment doesn't need to know the name of the column, though I'm not sure it's a better solution.
_
// In my DB Helper
public Cursor getTitleCursor() {
String query = "SELECT title AS displayCol FROM myTable"
return db.rawQuery(query, null);
}
// In my DB Helper
public Cursor getGenreCursor() {
String query = "SELECT genre AS displayCol FROM myTable"
return db.rawQuery(query, null);
}
// In my fragment:
DBHelper helper = new DBHelper(getActivity());
Cursor cursor = helper.getTitleCursor();
adapter = new CustomCursorAdapter(getActivity(), cursor);
// The constructor of my CursorAdapter:
public CustomCursorAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
inflater = LayoutInflater.from(context);
}
// In my cursor adapter
public void bindView(View view, Context context, Cursor cursor) {
TextView title = (TextView) view.findViewById(R.id.row_title);
String titleText = cursor.getString(cursor.getColumnIndex("displayCol"));
title.setText(titleText);
}
Related
I have created a ListView using CursorAdapter . Now I am Trying to update the ListView and Refresh the value to the ListView .
But I am not able to figure out . How to work with Loader or changeCursor() to refresh my ListView
Below is My code of setting the CursorAdapter :
//SucessFully done here
SQLDataSore datastore = new SQLDataSore(PrintContent.this);
Cursor cursor = datastore.getJSONData();
final CursorDemo cursorDemo = new CursorDemo(PrintContent.this, cursor);
list_View.setAdapter(cursorDemo);
My Button onClick I am updating the Value into the Database
//SucessFully Done
btn_check.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View view ) {
String editTextValue = edit_check.getText().toString();
if (editTextValue!=null) {
SQLDataSore sqlDataSore = new SQLDataSore(PrintContent.this);
Cursor cursor_update = sqlDataSore.updateData(editTextValue);
//Here How Should I update my ListView ...?
}
}
My UpdateData Method:
public Cursor updateData(String editContent){
SQLiteDatabase updateContent = getReadableDatabase();
Cursor cursor_update = updateContent.rawQuery( "update " +TABLE_NAME + " set content = '"+ editContent
+"' "+" where _id = 357", null);
return cursor_update;
}
CursorDemo Class
public class CursorDemo extends CursorAdapter{
public CursorDemo(Context context, Cursor c) {
super(context, c , false);
// TODO Auto-generated constructor stub
}
#Override
public void changeCursor(Cursor cursor) {
// TODO Auto-generated method stub
super.changeCursor(cursor);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// TODO Auto-generated method stub
TextView txt_content = (TextView) view.findViewById(R.id.txt_content);
TextView txt_likes_count = (TextView) view.findViewById(R.id.txt_likescount);
TextView txt_name = (TextView) view.findViewById(R.id.txt_name);
TextView txt_display_name = (TextView) view.findViewById(R.id.txt_display_name);
txt_content.setText(cursor.getString(cursor.getColumnIndex("content")));
}
#Override
public View newView(Context context , Cursor cursor, ViewGroup viewGroup) {
// TODO Auto-generated method stub
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.message_row_view, viewGroup ,false);
return view;
}
}
Any Help is Appreciated...
});
If CursorDemo extends CursorAdapter, then you have to use adapter.swapCursor(cursor_update);
That should swap the old cursor out for the new one and reload the data. With swapCursor, the old cursor is not closed.
In your CursorDemo you have to owerwrite changeCursor() method and reset the Cursor if you have indexer you have to set it's cursor too.
#Override
public void changeCursor(Cursor cursor) {
mIndexer.setCursor(cursor);
super.changeCursor(cursor);
}
public void changeCursor (Cursor cursor)
Added in API level 1 Change the underlying cursor to a new cursor. If
there is an existing cursor it will be closed.
Parameters cursor The new cursor to be used
Also try for below method if it's apt for your requirement.
Set a FilterQueryProviderand pass your key to that filter.
final Cursor oldCursor = adapter.getCursor();
adapter.setFilterQueryProvider(myQueryProvider);
adapter.getFilter().filter(editTextValue, new FilterListener() {
public void onFilterComplete(int count) {
// assuming your activity manages the Cursor
// (which is a recommended way)
stopManagingCursor(oldCursor);
final Cursor newCursor = adapter.getCursor();
startManagingCursor(newCursor);
// safely close the oldCursor
if (oldCursor != null && !oldCursor.isClosed()) {
oldCursor.close();
}
}
});
private FilterQueryProvider myQueryProvider = new FilterQueryProvider() {
public Cursor runQuery(CharSequence searchKey) {
// assuming you have your custom DBHelper instance
// ready to execute the DB request
return sqlDataSore.updateData(searchKey);;
}
};
PS : The Cursor must include a column named _id or this class will not work see this.
btn_check.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View view ) {
String editTextValue = edit_check.getText().toString();
if (editTextValue!=null) {
SQLDataSore sqlDataSore = new SQLDataSore(PrintContent.this);
Cursor cursor_update = sqlDataSore.updateData(editTextValue);
cursorDemo.swapCursor(cursor_update);
//or cursorDemo=new CursorDemo(this,cursor_update);
list_View.setAdapter(cursorDemo);
}
}
Put this on the activity where declare the ListView . Just create a new adapter and put it in new cursor then recreate it or swap the cursor. make sure your listview or adapter not constant.
you could call
adapter.notifyDataSetChanged();
".java.lang.IllegalArgumentException: column '_id' does not exist ...althouh I have _id field in to my db table" means that the value of "cursor" in your code is wrong.
Check the code of getting the value of "cursor" please. A cursor must have a column named '_id'。
This is my suggestion
If you want to adapt/replace new cursor value to your list view , you should remove the old cursor from adapter and add new cursor value to the adapter.And finally adapt this adapter to listview using listview.setadapter(CursorAdapter) as follows.
liveTagListCursor = ctx.getContentResolver().query(
LiveTagProvider.TAG_LIST_URI, null, null, null, null);
tagCursorAdapter = new LiveTagListCursorAdapter(getActivity(),
liveTagListCursor);
tagCursorAdapter.swapCursor(liveTagListCursor);
listview.setAdapter(tagCursorAdapter);
I have a list view that is being populated from an SQLite database using the SimpleCursorAdapter. One of the columns being returned in the cursor is an integer value 0 or 1. In my list view, I would like to display this in a more friendly form (ie. "Yes" or "No") and possibly with different text colors for each. Here is my source:
Cursor c = dbHelper.fetchAllItems();
startManagingCursor(c);
String[] from = {"deployed", "designation", "serial"};
int[] to = {R.id.deployed, R.id.designation, R.id.serial};
setListAdapter(new SimpleCursorAdapter(this, R.layout.list_item, c, from, to));
How would I conditionally switch elements and/or properties in the layout when the SimpleCursorAdapter simply maps each view to a column name. (Is it safe to assume I can't use SimpleCursorAdapter to accomplish this?)
Solved by adding a custom adapter, extending CursorAdapter
Modification:
Cursor c = dbHelper.fetchAllItems();
startManagingCursor(c);
setListAdapter(new RowAdapter(this, c));
New nested class:
private static class RowAdapter extends CursorAdapter {
public RowAdapter(Context context, Cursor c) {
super(context, c);
}
public void bindView(View view, Context context, Cursor c) {
TextView vDesignation = (TextView) view.findViewById(R.id.designation);
TextView vSerial = (TextView) view.findViewById(R.id.serial);
TextView vDeployed = (TextView) view.findViewById(R.id.deployed);
String designation = c.getString(c.getColumnIndexOrThrow("designation"));
String serial = c.getString(c.getColumnIndexOrThrow("serial"));
int deployed = c.getInt(c.getColumnIndexOrThrow("deployed"));
vDesignation.setText(designation);
vSerial.setText(serial);
vDeployed.setText(deployed > 0 ? R.string.yes : R.string.no);
vDeployed.setTextColor(deployed > 0 ? view.getResources().getColor(R.color.yes) : view.getResources().getColor(R.color.no));
}
public View newView(Context context, Cursor c, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.list_item, parent, false);
bindView(view, context, c);
return view;
}
}
I'm trying to populate listview from my SQLite database... this is how I get my data from database:
Cursor c = database.rawQuery("SELECT * FROM " + TableName, null);
int Column1 = c.getColumnIndex("uri");
int Column2 = c.getColumnIndex("file");
int Column3 = c.getColumnIndex("id");
c.moveToFirst();
if (c != null) {
do {
String uri = c.getString(Column1);
String file = c.getString(Column2);
int id = c.getInt(Column3);
} while (c.moveToNext());
}
I would normally add an array to listview like that:
ListView my_listview2 = (ListView) findViewById(R.id.listView1);
String my_array[] = {"Android", "iPhone"};
my_listview2.setAdapter(new ArrayAdapter<String>(this, R.layout.row, R.id.my_custom_row, my_array));
How can I make an array to setadapter from my sql query?
The best way to do this is to use a CursorAdapter or a SimpleCursorAdapter. This will give you the best performance and once you figure it out you'll find it's the simplest approach when using a SQLite db.
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
Below is a simple CustomCursorAdapter that I use frequently. Just add the CustomCursorAdapter class as an inner class.
protected class CustomCursorAdapter extends SimpleCursorAdapter {
private int layout;
private LayoutInflater inflater;
private Context context;
public CustomCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.layout = layout;
this.context = context;
inflater = LayoutInflater.from(context);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Log.i("NewView", newViewCount.toString());
View v = inflater.inflate(R.layout.list_cell, parent, false);
return v;
}
#Override
public void bindView(View v, Context context, Cursor c) {
//1 is the column where you're getting your data from
String name = c.getString(1);
/**
* Next set the name of the entry.
*/
TextView name_text = (TextView) v.findViewById(R.id.textView);
if (name_text != null) {
name_text.setText(name);
}
}
Create an instance of the CustomCursorAdapter like so...
You'll need to create your cursor just like you're already doing.
protected String[] from;
protected int[] to;
//From is the column name in your cursor where you're getting the data
//to is the id of the view it will map to
from = new String[]{"name"};
to = new int[]{R.id.textView};
CustomCursorAdapter adapter = new CustomCursorAdapter(this, R.layout.list, cursor, from, to);
listView.setAdapter(adapter);
I found working with the notepad tutorial very useful for learning about this.
It shows you how to implement the listview using the sqlite database in very easy steps.
http://developer.android.com/resources/tutorials/notepad/index.html
I am trying to create Custom Cursor adapter and attach it to my listview.
Though I am not yet there to create textboxes and set values inside my adapter,
my code currently throws a runtime exception when I try to call super(ctx, c);
What could be wrong? Searched all over the web & couldn't get it. Thanks in advance!
Custom Cursor adapter:
public class CustomCursorAdaptor extends CursorAdapter {
private Context context;
private int layout;
public CustomCursorAdaptor (Context ctx, int layout, Cursor c, String[] from, int[] to) {
super(ctx, c);
this.context = ctx;
this.layout = layout;
}
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return(new View(context));
}
#Override
public void bindView(View v, Context context, Cursor c) {
}
}
and my Activity:
public class DynamicScrollView extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context ctx=getBaseContext();
RelativeLayout newLayout=new RelativeLayout(ctx);
ListView lv=new ListView(ctx);
SQLiteDatabase db;
db = ctx.openOrCreateDatabase("TShow.db", SQLiteDatabase.OPEN_READONLY, null);
db.setVersion(1);
db.setLocale(Locale.getDefault());
db.setLockingEnabled(true);
Cursor cur = db.query("control", new String[] {"id"}, "parent_id=2", null, null, null, null);
CustomCursorAdaptor adapter = new CustomCursorAdaptor(ctx, lv.getId(), cur, new String[] {"id"}, new int[] {2});
lv.setAdapter(adapter);
newLayout.addView(lv);
setContentView(newLayout);
}
}
I really don't know much about the base context, which you are passing to your CursorAdaptor here, but I understand that usually you should rather be using your Activity as the context. Activity is a subclass of Context, in case you did not know.
So, in stead of:
new CustomCursorAdaptor(ctx, lv.getId(), cur, new String[] {"id"}, new int[] {2});
... you could try:
new CustomCursorAdaptor(this, lv.getId(), cur, new String[] {"id"}, new int[] {2});
Cursor adapter expects to have a column _id which it uses as index. I added another column as _id in the select and it worked! Updated code:
Cursor cur = db.query("control", new String[] {"id as _id", "id"}, "parent_id=2", null, null, null, null);
I traced it back from the exception description which said: column '_id' does not exist
Thank you for the golden tip about the _id column which is needed for the ListView to work.
#dmg: you must not name your _id column with the (native)SQL 'AS' statement. Just add the '_id' column without changing it.
i have been having this issue for some time now, and have not gotten an answer for it yet. i have this custom Cursor adapter which i use to populate a list view from an sqlite database. Now my issue is that i want to populate the listview based on certain conditions.An example is if the condition is important, the listview should display only data that fits into that criteria and so on. I already have working methods that query the database accordingly.
now my problem is that, i can't seem to populate the listviews based on those methods and conditions without:
1) creating a copy of the exact same custom cursor adapter and just changing the names variables.
2) creating a copy of the exact xml layout and changing the id's.
As i say, its working this way, but i feel am having unnecessary classes and xml layout since its exactly the same thing. I know am doing something wrong, i just don't know what. Please any help and explanation would be appreciated. here is the necessary part of the code Code for the CustomCursorAdapter:
public class ViewItems extends ListActivity implements OnItemClickListener{
DBAdapter adapter;
Cursor cursor;
ListView list;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_list);
adapter = new DBAdapter(this);
adapter.open();
fillData();
list = (ListView)findViewById(android.R.id.list); // default android listView id
list.setOnItemClickListener(this);
}
// Different method calls
protected void fillImportantData() {
Cursor cursor = adapter.retrieveImportant();
startManagingCursor(cursor);
String[] from = new String[]{DBAdapter.NAME, DBAdapter.DATE, DBAdapter.TIME, DBAdapter.PRIORITY};
int[] to = new int[]{R.id.viewNameId, R.id.viewDateId, R.id.viewTimeId};
customCursorAdapter items = new customCursorAdapter(this, R.layout.view_items, cursor, from, to);
setListAdapter(items);
}
public class customCursorAdapter extends SimpleCursorAdapter {
private int layout;
Context context;
public customCursorAdapter(Context context, int layout, Cursor cursor, String[]from, int[] to) {
super(context, layout, cursor, from, to);
this.layout = layout;
this.context = context;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder;
if(view != null){
holder = new ViewHolder();
holder.viewName = (TextView)view.findViewById(R.id.viewNameId);
holder.viewStartDate = (TextView)view.findViewById(R.id.viewDateId);
holder.viewStartTime = (TextView)view.findViewById(R.id.viewTimeId);
view.setTag(holder);
}else{
holder = (ViewHolder)view.getTag();
}
int namecol = cursor.getColumnIndex(DBAdapter.NAME);
String name = cursor.getString(namecol);
if(holder.viewName != null){
holder.viewName.setText(name);
holder.viewName.setTextColor(Color.RED);
}
String startDate = cursor.getString(cursor.getColumnIndex(DBAdapter.DATE));
holder.viewStartDate.setText(startDate);
String startTime = cursor.getString(cursor.getColumnIndex(DBAdapter.TIME));
holder.viewStartTime.setText(startTime);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(layout, parent, false);
return view;
}
#Override
public long getItemId(int id){
return id;
}
#Override
public Object getItem(int position){
return position;
}
}
static class ViewHolder{
TextView viewName;
TextView viewStartDate;
TextView viewStartTime;
}
}
// methods in database
public Cursor retrieveAll(){
String[] resultColumns = new String[] {KEY_ID, NAME DATE, TIME, PRIORITY};
Cursor cursor = db.query(DATABASE_TABLE, resultColumns, null, , null, null, null);
return cursor;
}
public Cursor retrieveImportant(){
String[] resultColumns = new String[] {KEY_ID, NAME DATE, TIME, PRIORITY};
String[] condition = {"important"};
Cursor cursor = db.query(DATABASE_TABLE, resultColumns, PRIORITY + "=" + "?", condition, null, null, null);
return cursor;
}
If you change the data you wish to display, you will need to run a fresh query on the database and get a Cursor back that reflects that changed data. Depending on the nature of the changes, this may require a fresh CursorAdapter or merely a call to changeCursor(). If the new query returns the same columns and you want them displayed the same way, changeCursor() is probably sufficient. Otherwise, you will need to create a new CursorAdapter and call setAdapter() on your ListView to switch over to it.
You only need a different row layout if you are truly changing the row layout. You do not need to change IDs just for grins. Since you are not doing this in the code you have shown above, I am unclear what specifically you are worried about.