I'm working on my first Android app and can't figure out how to get my SimpleCursorAdpater to populate the view. The cursor that I'm passing in has results in it, so the problem must be somewhere in instantiating the adapter or in binding it to the view. I'm sort of at my wits end since no exceptions are thrown and I can't really step
into setListAdapter.
Here is how i get my cursor in the first place:
Searches searches = new Searches(this);
SQLiteDatabase db = searches.getReadableDatabase();
//select _id, Name, Search FROM Searches;
Cursor c = db.query(
SearchConstants.TABLE_NAME,
FROM, null, null, null,
null, null);
startManagingCursor(c);
And this is the schema do my db:
CREATE TABLE Searches (_id INTEGER PRIMARY KEY, Name Text, Search TEXT)
Here are the two lines where things start to fall apart:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.search, cursor, FROM, TO);
setListAdapter(adapter);
My main layout looks like this:
<ListView
android:id="#android:id/android:list"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#android:id/android:empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/empty" />
Here is the view to fill with each result:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10sp">
<TextView
android:id="#+id/_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/colon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=": "
android:layout_toRightOf="#id/name" />
<TextView
android:id="#+id/search"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textStyle="italic"
android:layout_toRightOf="#id/colon" />
</RelativeLayout>
Finally here are the static variables I used:
//search query stuff
private static String[] FROM = {SearchConstants._ID, SearchConstants.NAME_COLUMN, SearchConstants.SEARCH_COLUMN};
//where to paste search results
private static int[] TO = {R.id._id, R.id.name, R.id.search};
/**
* Table name
*/
public static final String TABLE_NAME = "Searches";
/**
* Name Column
*/
public static final String NAME_COLUMN = "Name";
/**
* Search Column
*/
public static final String SEARCH_COLUMN = "Search";
I think this is all of the relevant code. I have no idea how to proceed at this point, so any suggestions at all would be helpful.
Thanks,
brian
PS: Looks like theres a lot of great suggestions here - i'm not ignoring them i just havent had the chance yet. Thanks for the advice! At some point i'll go thru them all and try to give some feedback as to which things worked well for me.
You can step into the code if you have the source code. Luckily, Android is open source. To easily attach source code in Eclipse, see:
http://android.opensourceror.org/2010/01/18/android-source/
As for the problem itself, you said in a comment above that you iterate all of the items before creating the adapter. If you are not creating a new cursor after iteration, you probably need to rewind it or the adapter might think it's empty.
cursor.moveToFirst()
Please don't worry about any internal binding aspects. I'm sure there is an easy way out. Try the following:
First, just to ensure your cursor really has got data where it's needed, put the line
System.out.println("cursor.getCount()="+cursor.getCount());
right before the call of setAdapter(). But surely, you already tested to get a row count ;-) So the following might be more interesting.
To check if your binding fails, please test with:
android:id="#+id/android:list"
instead of :
android:id="#android:id/android:list"
in your main.xml. Same thing with: android:id="#+id/android:empty".
And if you still don't get results, you can also try using a list default xml-layout (like simple_list_item_1) for displaying, which would look like this:
ListAdapter adapter = new SimpleCursorAdapter(this,
// Use a template that displays a text view
android.R.layout.simple_list_item_1,
// Give the cursor to the list adapter
cursor,
// Map the NAME column in your database to...
new String[] {SearchConstants.NAME_COLUMN} ,
// ...the "text1" view defined in the R.layout.simple_list_item_1
new int[] {android.R.id.text1}
);
Just copy paste it into your activity and see what happens.
Hope you're done with that!
Just got the same problem and found how to allow the Simplecursoradapter creation to not fail.
In your cursor, the query of the database MUST contain the table primary key even if you don't need it ! If not it will fail and crash...
Hope it will help others with the same problem !
Alright, I noticed you used a column name with a capital letter. Make sure you use the exact identifier in the DB scheme (the sqlite column names are case sensitive). But in the code you provided the column identifiers match.
So, if the cursor you use really has got the data, try out the above code at first (instead of some custom layout) for creating a SimpleCursorAdapter and it should work. Here's another little example for the activity code (as I don't know yours):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.dbManager = new DatabaseManager(this);
setContentView(R.layout.main);
registerForContextMenu(getListView()); // catch clicks
if (!showList()) {
TextView tv = new TextView(this);
tv.setText(getString(R.string.txt_list_empty));
setContentView(tv);
}
}
private boolean showList() {
final Cursor c = dbManager.fetchListData();
startManagingCursor(c); // when the Activity finishes, the cursor is closed
if (!c.moveToFirst())
return false;
final SimpleCursorAdapter myAdapter = new SimpleCursorAdapter(
this, android.R.layout.simple_list_item_2, c,
new String[]{"name"} , new int[]{android.R.id.text1} );
setListAdapter(myAdapter);
return true;
}
Before spending a lot of time where you encounter problems, rather start where things are still working and take small steps for extensions. If you keep them simple, there's no great magic in using adapters.
You might try inserting a ViewBinder for debugging. You can use it to inspect which values are being passed for which views in the SimpleCursorAdaptor. Or just use it to manually do the binding yourself.
Something like this should work:
adapter.setViewBinder(new SimpleCursorBinder());
and then
public class SimpleCursorBinder implements SimpleCursorAdpater.ViewBinder {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
/* set breakpoints and examine incoming data. */
// returning false, causes SimpleCursorAdapter to handing the binding
boolean bound = false;
String columnName = cursor.getColumnName(columnIndex);
TextView bindingView = null;
int viewId = view.getId();
// could just use this opportunity to manually bind
if (columnName.equals(SearchConstants._ID)) {
bindingView = (TextView)(viewId == R.id._id ? view : null);
} else if (columnName.equals(SearchConstants.NAME_COLUMN)) {
bindingView = (TextView)(viewId == R.id.name ? view : null);
} else if (columnName.equals(SearchConstants.SEARCH_COLUMN)) {
bindingView = (TextView)(viewId == R.id.search ? view : null);
}
if (bindingView != null) {
bindingView.setText(cursor.getString(columnIndex));
bound = true;
}
return bound;
}
}
It doesn't look like you've done anything wrong, You haven't shown all your code though so it might be difficult to spot any errors.
Not sure if the line startManagingCursor(c) does this for you but in my examples i have the following lines after my query has completed. Given your example looks absolutely fine it could be your cursor needs resetting to the first item.
(Ah, just noticed kichik pointed this out , but i'll leave my example.)
if (c != null) {
c.moveToFirst();
}
My queries often look like:
public Cursor getQueryCursor()
{
Cursor c;
c = null;
try{
c = myDataBase.query(TABLE_MYTABLE, new String[] {
COLUMN_ID,COLUMN_LABEL, COLUMN_TEXT},
null,
null,
null,
null,
null);
if (c != null) {
c.moveToFirst();
}
}catch(Exception ec)
{
Log.w("MY_APP", ec.getMessage());
}
return c;
}
Then when applying your query result i also often put try/catch statements around it and add break points at these points (sometimes the getMessage() returns null but other properties of the exception will highlight the issue. I also check the out put from LogCat. I've often been able to work out the root of my problems with the following.
try{
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.search, cursor, FROM, TO);
setListAdapter(adapter);
}catch(IllegalStateException e)
{
Log.w("MyApp", e.getMessage());
}catch(Exception es)
{
Log.w("MyApp", es.getMessage());
}
Please check your SQLite database, it must have a column '_id' as a primary key.
I had same kind of problem, and finally figure it out with this...
Related
I have an app which does the following: an Activity with a ListView displays three items: Beginning, Intermediate, Advanced. Depending on the user's choice, the app should go to a Fragment with a ListView which displays all items from the underlying SQLiteDatabase where Level=Beginning or Intermediate or Advanced. This second step is not working for me. I've verified through the debugger that I have data in my database, so that's not the problem. Here's my code in the initial Activity - this is from the onItemClick method:
final String[] values = new String[] {
"Beginning", "Intermediate", "Advanced"
};
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Intent choice = new Intent(getApplicationContext(), com.MyKnitCards.project.StitchList.class);
Bundle dataBundle = new Bundle();
String chosenValue = values[position];
dataBundle.putString("Level",chosenValue);
choice.putExtras(dataBundle);
try {
startActivity(choice);
}
}
Here's the StitchList class, which is the Fragment class, and which is referenced in the code above:
public class StitchList extends FragmentActivity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.stitchfragment);
}
}
Here's the XML file for the Fragment, called stitchfragment.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<fragment android:id="#+id/frag_stitchlist"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_marginTop="?android:attr/actionBarSize"
class="com.MyKnitCards.project.ListFrag" />
<fragment android:id="#+id/frag_stitchdetail"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.MyKnitCards.project.DetailFrag" />
</LinearLayout>
Here's the ListFrag class. I'm using the Support Library and a CursorLoader with a ContentProvider, called StitchProvider; the SQLiteDatabase is called SQLData:
public class ListFrag<Cursor> extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String STITCHTABLE_BASEPATH = "MyStitches_tbl";
private static final String AUTHORITY = "com.MyKnitCards.project.SQLData";
public static final Uri STITCHES_URI = Uri.parse("content://" + AUTHORITY + "/" + STITCHTABLE_BASEPATH);
private static final String[] PROJECTION = new String[] { "_id", "stitchname" };
private SimpleCursorAdapter mAdapter;
private static final int LOADER_ID = 0;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Intent myData = getActivity().getIntent();
Bundle info = myData.getExtras();
String[] dataColumns = { "stitchname", "_id" };
int[] viewIDs = { R.id.frag_stitchlist };
mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_1, null, dataColumns, viewIDs, 0);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, info, (LoaderCallbacks<Cursor>) this);
}
public void onListItemClick(ListView l, View v, int position, long id) {
String item = (String) getListAdapter().getItem(position);
DetailFrag frag = (DetailFrag) getFragmentManager().findFragmentById(R.id.frag_stitchdetail);
if (frag != null && frag.isInLayout()) {
frag.setText(item);
}
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String selection = "stitchlevel='" + args.getString("Level") + "'";
return (Loader<Cursor>) new CursorLoader(getActivity(), STITCHES_URI,
PROJECTION, selection, null, null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
switch (loader.getId()) {
case LOADER_ID:
mAdapter.swapCursor((android.database.Cursor) cursor);
break;
}
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
The onListItemClick method is for displaying data in the details Fragment, but I'm never getting this far. The list of items retrieved from the database based on the data in the Intent is never displayed.
Some possible issues/questions come to mind:
1) Is the syntax of my query in the onCreateLoader method correct? It should read, "stitchlevel='Beginning'", for example. I know the data in args.getString("Level") is valid because I've followed it through in the debugger, but is the syntax correct here? I'm assuming it should be standard SQL syntax, but...
2) In the assignment of value to viewIDs in the Fragment's onActivityCreated method, am I pointing to the correct place?
3) Similarly, in the next line, the SimpleCursorAdapter, is android.R.layout.simple_list_item_1 correct here? Or should it perhaps be R.layout.stitchfragment?
4) I put a breakpoint on the ContentProvider's query method, I never hit the breakpoint. Shouldn't I when the CursorLoader gets created? Furthermore, if I put a breakpoint on the List Fragment's onLoadFinished method, the cursor is null. What am I missing
5) I was told that dataColumns in the Fragment's onActivityCreated method should contain my table's _id column. Is that true? It seems odd to me, since the list will only display one piece of information: the stitchname. However, whether _id is included or not here, the Fragment list does not display anything
6) Is it proper for me to pass the Bundle, info, to the CursorLoader through getLoaderManager.initLoader, as I do in the Fragment's onActivityCreatedMethod?
7) I've seen examples of setListAdapter being called before getLoaderManager().initLoader() in the Fragment's onActivityCreated method and I've seen examples where setListAdapter is called after. Which is correct? Neither seems to help me....
I have been able to get a Fragment to display if I simply do this:
Intent myData = getActivity().getIntent();
Bundle info = myData.getExtras();
String level = info.getString("Level");
String[] values = new String[] {level, level};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
So I know I can display data in the Fragment; it just doesn't seem to be working with the CursorLoader and ContentProvider. I hope this isn't information overload; my apologies if it is. If anyone has any ideas, I'd be most grateful.
1) Is the syntax of my query in the onCreateLoader method correct? It
should read, "stitchlevel='Beginning'", for example. I know the data
in args.getString("Level") is valid because I've followed it through
in the debugger, but is the syntax correct here? I'm assuming it
should be standard SQL syntax, but
Yes, it's correct. Even better would be:
String selection = "stitchlevel= ?";
String selectionArgs = new String[] {args.getString("Level")};
return new CursorLoader(getActivity(), STITCHES_URI, PROJECTION, selection, selectionArgs, null);
2) In the assignment of value to viewIDs in the Fragment's
onActivityCreated method, am I pointing to the correct place? 3)
Similarly, in the next line, the SimpleCursorAdapter, is
android.R.layout.simple_list_item_1 correct here? Or should it perhaps
be R.layout.stitchfragment?
No. The int array that you supply to the adapter represents the ids from the row layout that is used in the adapter and not the id of the fragment like you wrote it. If you use the android.R.layout.simple_list_item_1(which consists of only a TextView) than you have to provide the id of that TextView, which is android.R.id.text1:
String[] dataColumns = { "stitchname"};
int[] viewIDs = { android.R.id.text1 };
mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_1, null, dataColumns, viewIDs, 0);
4) I put a breakpoint on the ContentProvider's query method, I never
hit the breakpoint. Shouldn't I when the CursorLoader gets created?
Furthermore, if I put a breakpoint on the List Fragment's
onLoadFinished method, the cursor is null. What am I missing
I think you didn't do what I recommended you on your last question. The provider's query method should have been at least called and this not happening just leaves one option. I've noticed that you cast the Loaders and you're missing the Override annotation on the callback methods from LoaderManager.LoaderCalbbacks. Add the Override annotation to those methods:
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String selection = "stitchlevel= ?";
String selectionArgs = new String[] {args.getString("Level")};
return new CursorLoader(getActivity(), STITCHES_URI,
PROJECTION, selection, selectionArgs, null);
}
and see what happens. If you get errors make sure you used the correct imports and either only use the classes from the compatibility package or the normal ones(you could easily delete all imports from the file and then re-import everything and use the classes with android.support.v4). Just a wild guess.
5) I was told that dataColumns in the Fragment's onActivityCreated
method should contain my table's _id column. Is that true? It seems
odd to me, since the list will only display one piece of information:
the stitchname. However, whether _id is included or not here, the
Fragment list does not display anything
Cursor based adapters require that the used Cursor must contain a column named _id(see the documentation of the CursorAdapter class, the super class of SimpleCursorAdapter). It doesn't need to be present in the String array which is set into the adapter.
6) Is it proper for me to pass the Bundle, info, to the CursorLoader
through getLoaderManager.initLoader, as I do in the Fragment's
onActivityCreatedMethod?
Yes. But regarding the id, be consistent, if you're going to use LOADER_ID use it everywhere and not just in some places in your code. Or even better, if you're going to use just one Loader just use 0 everywhere(so there is no need to test for the LOADER_ID in the onLoadFinished method).
7) I've seen examples of setListAdapter being called before
getLoaderManager().initLoader() in the Fragment's onActivityCreated
method and I've seen examples where setListAdapter is called after.
Which is correct?
Both can be used. I would set the adapter and then initialize the Loader.
I'm using SimpleCursorAdaptor and a ListView to display the values in my SQLite database rows. One of the values in my row is a date (column 'date'). Rather than display this date I need to run this through a method that will return another string based on what the date is. This is the value I want displayed in my list rather than the actual value taken straight from the Database.
In short I wish to display all values from my database table row except for one, where I need to change it before displaying it.
Here is my code:
public class BinCollectionDayListActivity extends ListActivity{
//
private static final String fields[] = { "name", "date", BaseColumns._ID };
//
public void onCreate(Bundle savedInstanceState) {
//
super.onCreate(savedInstanceState);
//
DatabaseHelper helper = new DatabaseHelper(this);
SQLiteDatabase database = helper.getWritableDatabase();
Cursor data = database.query("names", fields, null, null, null, null, null);
CursorAdapter dataSource = new SimpleCursorAdapter(this, R.layout.binrow, data, fields, new int[] { R.id.name, R.id.date });
dataSource.getCursor().requery();
//
ListView view = getListView();
view.setHeaderDividersEnabled(true);
setListAdapter(dataSource);
//
helper.close();
database.close();
}
}
As you can tell I am pretty new to Android development and would love to know what the best approach would be to achieving the desired result.
Thanks in advance,
Tony
Two options that I've used before:
Array Adapter (Preferred):
Create an ArrayAdapter and populate the Cursor data into your ArrayAdapter.
http://anujarosha.wordpress.com/2011/11/17/how-to-create-a-listview-using-arrayadapter-in-android/
ViewBinder: On your Cursor, you can setup/specify a ViewBinder where you can check the data that's about to be mapped, perform some logic on it, and spit out a different result if desired. This is probably exactly what you're looking for, but do consider the ArrayAdapter as it tends to give you better control and it's a pain to switch these things later on.
Changing values from Cursor using SimpleCursorAdapter
I was looking for an alternative to a spinner, since the first item is always selected (which causes me issues), and I found some examples for using an AlertDialog with a list instead.
I am having two problems:
The list is displaying and is formatted ok, but there are no values in it. I know the query is returning, and the cursor/adapter has the data in it.
This may be a symptom of #1 - but when I select a blank row, the Cursor cursor2 = (Cursor) ((AdapterView) dialog).getItemAtPosition(which); statement causes a crash (it's a ClassCastException).
I had similar code previously which set the adapter to a spinner object, and the data was displaying fine.
I don't think the adapter is getting set correctly, and I have been unable to come up with a solution thus far.
Any thoughts?
Thanks!
btnDenomination.setOnClickListener(new View.OnClickListener()
{
public void onClick(View w)
{
Cursor cursor = coinDB.myDataBase.rawQuery("select _id, denomination_desc from denomination", null); // must select the _id field, but no need to use it
startManagingCursor(cursor); // required in order to use the cursor in
String[] from = new String[] {"denomination_desc" }; // This is the database column name I want to display in the spinner
int[] to = new int[] { R.id.tvDBViewRow }; // This is the TextView object in the spinner
cursor.moveToFirst();
SimpleCursorAdapter adapterDenomination = new SimpleCursorAdapter(CoinsScreen.this,
android.R.layout.simple_spinner_item, cursor, from, to );
adapterDenomination.setDropDownViewResource(R.layout.db_view_row);
new AlertDialog.Builder(CoinsScreen.this)
.setTitle("Select Denomination")
.setAdapter(adapterDenomination, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
Cursor cursor2 = (Cursor) ((AdapterView<?>) dialog).getItemAtPosition(which);
strDenomination_id = cursor2.getString(0); // Gets column 1 in a zero based index, the first column is the PKID. this could
// be avoided by using a select AS statement.
Log.d("Item Selected", strDenomination_id );
TextView txtDenomination = (TextView) findViewById(R.id.textDenomination);
txtDenomination.setText(cursor2.getString(1));
dialog.dismiss();
}
}).create().show();
}
});
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="#+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:text=""
android:id="#+id/tvDBViewRow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF0000" />
</LinearLayout>
Are you sure R.id.tvDBViewRow is the id of the TextView in the layout android.R.layout.simple_spinner_item ? From this, the TextView's id should be android.R.id.text1.
So new answer for the second issue :)
I think you should reuse the initial cursor instead of trying to get a new one... Can you try to do :
adapterDenomination.moveToPosition(which);
strDenomination_id = adapterDenomination.getString(0);
in the onClick() ?
i'm making select statement and it works fine
the problem is selecting more than thousands of records ate one and this cause the program too slow.
is there a possibility to select fifty by fifty and when select the first fifty record show them then add the next fifty record to them.
how can i do that .
thanks in advance ...
Use LIMIT/OFFSET Clauses is selection statement
I haven't worked on that but can give some idea reagarding that. You can use AsynTask here. In the doingInbackground() you can get the records and then you can call publishProgress() when 50 records are fetched and update the UI.
UPDATE:
You can use the LIMIT/OFFSET clause that Kiran said to get the limit of the record fetched and can update the UI using AsyncTask.
Here is the code you need to back your AutoCompleteTextView with a cursor adapter.
#Override
protected void onResume() {
super.onResume();
text = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
final AdapterHelper h = new AdapterHelper(this);
Cursor c = h.getAllResults();
startManagingCursor(c);
String[] from = new String[] { "val" };
int[] to = new int[] { android.R.id.text1 };
CursorAdapter adapter = new MyCursorAdapter(this,
android.R.layout.simple_dropdown_item_1line, c,
from, to);
adapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
if (constraint == null) {
return h.getAllResults();
}
String s = '%' + constraint.toString() + '%';
return h.getAllResults(s);
}
});
text.setAdapter(adapter);
}
class MyCursorAdapter extends SimpleCursorAdapter {
public MyCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
}
public CharSequence convertToString(Cursor cursor) {
return cursor.getString(cursor.getColumnIndex("val"));
}
}
The database that I am using has 3k rows of data in it and the Autocomplete works fine.
The things to note are that you need make sure that the your adapter puts the correct value in the text box once a user selects it. Do this with the convertToString method (at the end of the snippet above). You get to this method by extending SimpleCursorAdapter and overriding the method as shown.
Then you need to provide a FilterQueryProvider to your adapter. This allows your query to be run with the where clause of your typed text. If you have a huge dataset, then setting the threshold large enough (either programatically, or in xml) will prevent the filter query running until it will return a suitably sized resultset.
Hope this is useful.
Anthony Nolan
I'm quite new to Android development (started 2 days ago) and have been through a number of tutorials already. I'm building a test app from the NotePad exercise (Link to tutorial) in the Android SDK and as part of the list of notes I want to display a different image depending on the contents of a database field i've called "notetype". I'd like this image to appear in the List view before each notepad entry.
The code in my .java file is:
private void fillData() {
Cursor notesCursor = mDbHelper.fetchAllNotes();
notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor);
String[] from = new String[]{NotesDbAdapter.KEY_NOTENAME, NotesDbAdapter.KEY_NOTETYPE};
int[] to = new int[]{R.id.note_name, R.id.note_type};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, notesCursor, from, to);
setListAdapter(notes);
}
And my layout xml file (notes_row.xml) looks like this:
<ImageView android:id="#+id/note_type"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/default_note"/>
<TextView android:id="#+id/note_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
I just really have no clue how I'd go about fetching the right drawable depending on the type of note that has been selected. At the moment I have the ability to select the type from a Spinner, so what gets stored in the database is an integer. I've created some images that correspond to these integers but it doesn't seem to pick things up.
Any help would be appreciated. If you need more info then please let me know.
You might want to try using a ViewBinder. http://d.android.com/reference/android/widget/SimpleCursorAdapter.ViewBinder.html
This example should help:
private class MyViewBinder implements SimpleCursorAdapter.ViewBinder {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
int viewId = view.getId();
switch(viewId) {
case R.id.note_name:
TextView noteName = (TextView) view;
noteName.setText(Cursor.getString(columnIndex));
break;
case R.id.note_type:
ImageView noteTypeIcon = (ImageView) view;
int noteType = cursor.getInteger(columnIndex);
switch(noteType) {
case 1:
noteTypeIcon.setImageResource(R.drawable.yourimage);
break;
case 2:
noteTypeIcon.setImageResource(R.drawable.yourimage);
break;
etc…
}
break;
}
}
}
Then add it to your adapter with
note.setViewBinder(new MyViewBinder());