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.
Related
INTRODUCTION
I've got an app which consists on an Acitivity where I create some elements and then I save this elements on a ListFragment. This stuff works fine, but the problem comes when I try to delete an element from the list.
Briefly, the listFragment doesn't refresh when I delete an element. If I go back to main Activity and then I enter again to the ListFragment, then the element that I deleted doesn't appear, but the thing would be to refresh this list at the moment I delete an element.
Have to say that I'm a bit confused because at first, it was doing this right, but I don't know what I have touched that now does not do it.
CODE
This are relevant code snippets of ListFragment:
public class MyPlacesListFragment extends ListFragment {
//...
final class PlacesCursorAdapter extends ResourceCursorAdapter {
//...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getAdapter();
}
public void getAdapter() {
Cursor c = getActivity().getContentResolver().query(PlacesProvider.CONTENT_URI, PROJECTION, null, null, null);
mCursorAdapter = new PlacesCursorAdapter(getActivity(), c);
setListAdapter(mCursorAdapter);
}
private void deleteItem(long id){
Uri uri = ContentUris.withAppendedId(PlacesProvider.CONTENT_URI, id);
getActivity().getContentResolver().delete(uri, null, null);
}
I have to say that I work with dataBase and ContentProvider, but these work fine, I've tested them with other apps.
Also, I call notifyChange() on the Insert, Update, and Delete methods of the Provider this way:
getContext().getContentResolver().notifyChange(uri, null);
Just call this:
mCursorAdapter.notifyDataSetChanged();
After you made changes to your underlying data.
Also, I'd suggest renaming your getAdapter() method, as it has a misleading name IMHO. I'd expect it to return always the same adapter, while you seem to use it to initialize a new adapter.
What better way to show a progress indicator while my listview is not filled with data of database?
I found some examples of how to do this, using assynctask, but in my case, I am using Loader /CursorLoader.
public class TestActivity extends SherlockFragmentActivity implements
LoaderCallbacks<Cursor> {
SimpleCursorAdapter mAdapter;
ListView mListView;
private static final String[] UI_BINDING_FROM = new String[] {
TestDBAdapter.KEY_NAME, TestDBAdapter.KEY_ICON };
private static final int[] UI_BINDING_TO = new int[] { R.id.text, R.id.icon };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_Test);
mListView = (ListView) findViewById(R.id.listview);
mAdapter = new TestAdapter(getApplicationContext(),
R.layout.list_item_Test, null, UI_BINDING_FROM,
UI_BINDING_TO, 0);
mListView.setAdapter(mAdapter);
getSupportLoaderManager().initLoader(0, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri uri = ContentProviderTest.CONTENT_URI;
CursorLoader cursorLoader = new CursorLoader(
this,
uri,
null,
null,
null,
null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
A possible solution, would be to create a new class extending ListFragment and use the setListShown() method , but I do not know if it is the best way to solve this issue.
Thanks
Add a small ProgressBar to your layout file, with its visibility set to "gone". Just before you create your CursorLoader, set its visibility to "visible". It will appear. In onLoadFinished, set the ProgressBar visibility to "gone". It will disappear, and your ListView will load.
I'd use the small style progressbar. To learn more about this, see the reference docs for android.widget.ProgressBar.
BTW, visibility is controlled with View.setVisibility.
In addition to the right answer: it is a good idea in onLoadFinished() to have this check:
if (cursor.getCount() > 0) {
getView().findViewById(R.id.loadingPanel).setVisibility(View.GONE);
getView().findViewById(android.R.id.list).setVisibility(View.VISIBLE);
}
Otherwise, in case of relying on your curstomService to fill the db with data, the cursor may be empty and result would be no progress bar neither list with items showing up.
I have a costumCursorAdapter in a listView.
I also have a cursorLoader to swap the costumCursorAdapter when data is changed in the data base. DB data is entered by a user initiated search.
None of these advices worked, Google was no help - nothing stoped the progress bar once set to visible-
i.e. progress_bar.setVisibility(View.Gone);
Eventually, as a simple and 'only for now' sulotion-
I created a global variable to act as a counter int count = 0.
It is reset to 0 with every search (in the onClick method of a button).
In the bindView of the customAdapter, in the bottom of this code block- I initiated the count with count ++.
At the top of the code block I check if the count reached 4. If it is, I hide the progress bar:
if (count==4){
pb.setVisibility(View.GONE);
}
This way, when the customAdapter binds the 4th view,I know it's resonable to stop the progress bar.
I never have less than 4 items on the list.
Hope this helps someone.
I'm trying to output a list from an SQLite database and am getting this exception:
android.content.res.Resources$NotFoundException: File from xml type layout resource ID #0x102000a
After checking around on similar questions, I've made sure my ListView is defined as #id/android:list but still get the same exception. The problem occurs when the onCreate method in the ListActivity class completes. The getAllDiaryEntries() method does get the data from the db, but again, once it comes back to the ListActivity class and onCreate finishes I get the exception. Here's the relevant parts of code.
This is the ListActivity class:
public class DiarySchedule extends ListActivity
{
private DiaryDataSource datasource;
private static final String TAG = "DiaryDbAdapter";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.diary_schedule);
datasource = new DiaryDataSource(this);
datasource.open();
List<DiaryEntry> values = datasource.getAllDiaryEntries();
ArrayAdapter<DiaryEntry> adapter = new ArrayAdapter<DiaryEntry>(this,
android.R.id.list, values);
setListAdapter(adapter);
}
Next we have the getAllDiaryEntries() method:
public List<DiaryEntry> getAllDiaryEntries()
{
List<DiaryEntry> diaryEntries = new ArrayList<DiaryEntry>();
Cursor cursor = database.query(DiaryDbAdapter.DIARY_TABLE,
allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
DiaryEntry diaryEntry = cursorToDiaryEntry(cursor);
diaryEntries.add(diaryEntry);
cursor.moveToNext();
}
// Make sure to close the cursor
cursor.close();
return diaryEntries;
}
And the layout (not styled or anything yet):
<ListView
android:id="#id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
I'm still pretty new to Android so may have missed something simple, but thanks in advance for any help.
Edited - here's the cursortoDiaryEntry method
private DiaryEntry cursorToDiaryEntry(Cursor cursor)
{
DiaryEntry diaryEntry = new DiaryEntry();
diaryEntry.setId(cursor.getLong(0));
diaryEntry.setTitle(cursor.getString(1));
diaryEntry.setDate(cursor.getString(2));
diaryEntry.setDescription(cursor.getString(3));
return diaryEntry;
}
The constructor (the one you're using) of the ArrayAdapter is defined as follows:
public ArrayAdapter (Context context, int textViewResourceId, List<T> objects)
In here the textViewResourceId is "The resource ID for a layout file containing a TextView to use when instantiating views.". See here.
You should pass a layout file containing a <TextView/> element, using R.layout.layout_file.
dennisg has the right answer to fix your problem.
Might I suggest that you are making extra work by turning your cursor into an array? You can save some cycles by using your cursor directly to create your list adapter.
Cursor cursor = database.query(DiaryDbAdapter.DIARY_TABLE,
allColumns, null, null, null, null, null);
getActivity().startManagingCursor(cursor);
String[] from = new String[] { DiaryDbAdapter.DIARY_ENTRY };
int[] to = new int[] { R.id.ListItem1 };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(),
R.layout.listlayoutdouble, cursor, from, to);
setListAdapter(adapter);
Your from string[] contains the list of columns you wish to include in the display, the to int[] contains the resource id's you wish to put the data into (in matching order with the from array). Then the adapter callout specifies which row layout to use, what cursor and the two arrays to map the data to the view.
I'm having a problem populating my spinner with data from my SQLite database. Here's the code from my Activity. The Activity crashes with an Unable to start Activity ComponentInfo error where indicated with an arrow.
public class ProjectsActivity extends Activity {
private ReelDbAdapter dbHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.projects_select);
fillProjectSpinner();
}
private void fillProjectSpinner(){
// initialize cursor to manage data binding to spinner
Cursor projectCursor = null;
Spinner spnExistingProjects = (Spinner)findViewById(R.id.spnExistingProject);
---> projectCursor = dbHelper.getExistingProjects();
//startManagingCursor(projectCursor);
/*
//get the list of project names from the database
String[] from = new String[] {dbHelper.clmProjectName};
//add a new item to the spinner for each of the rows in the database
int [] to = new int[]{R.id.txtViewProjectRow};
//initialize a cursor adapter (similar to ArrayAdapter when populating a spinner from a pre-defined array)
SimpleCursorAdapter projectAdapter = new SimpleCursorAdapter(this, R.layout.view_project_row, projectCursor, from, to);
//add all the rows to the spinner
spnExistingProjects.setAdapter(projectAdapter);
*/
}
Here's the code from the getExistingProjects method from my dbAdapter
public Cursor getExistingProjects() {
if(mDb == null)
{
this.open();
}
return mDb.query(dbTableProject, new String[] {clmProjectName, clmProjectShootingTitle, clmProjectJobNumber},
null, null, null, null, null);
}
Any clues on what I might be doing wrong?
TIA for any help.
Norm
Why don't you try making sure the query is returning something before returning the cursor in your method? Put a log line in that spits out the count of the cursor. Also, you should be able to see this easily while stepping through with the debugger.
Also, why assign null to the cursor's deceleration when you're just going to initialize it a few lines down. Do it all in one line.
Lastly, what db are you trying to one with that this.open() line? I obviously can't tell with just the code you've posted, but put a try catch around that whole thing and spit out the strackTrace. You should see your issue.
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...