So I'm developing an app over the summer. It stores items in the database, displays them in a listview (otherwise makes Toast telling the user its empty), and allows users to see details by clicking on one. Eventually I plan on having search criteria narrow down the list, but I'm not there yet.
My problem is that the listview seems to be populating, but the app makes Toast....
ResultsActivity.java
public class ResultsActivity extends FragmentActivity implements ResultsFragment.OnPlantSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_results);
}// method: FragmentActivity.onCreate()
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.results, menu);
return true;
}// method: FragmentActivity.onCreateOptionsMenu()
/* Custom methods */
//@Override
public void onPlantSelected(long id){
Intent intent = new Intent(this, PlantViewActivity.class);
//TODO confirm id
intent.putExtra(DBContentProvider.KEY_PLANT_ID, id);
startActivity(intent);
}// method: ResultsFragment.OnPlantSelectedListener.onPlantSelected(long)
}// class: ResultsActivity extends ListActivity
ResultsFragment.java
public class ResultsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
private static OnPlantSelectedListener emptyPlantSelectedListener = new OnPlantSelectedListener(){
@Override
public void onPlantSelected(long id){}
};
private static OnPlantSelectedListener plantSelectedListener = emptyPlantSelectedListener;
private static final String STATE_ACTIVATED_POSITION = "activated_position";
private int activatedPosition = ListView.INVALID_POSITION;
private SimpleCursorAdapter adapter;
public ResultsFragment(){}
/* Fragment Lifespan */
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
String[] dbPlantColumns = {DBContentProvider.KEY_GENUS_TEXT, DBContentProvider.KEY_SPECIES,
DBContentProvider.KEY_COMMON_NAME_GROUP};
int[] fragPlantFields = {R.id.result_item_txt_genus, R.id.result_item_txt_species,
R.id.result_item_txt_common_name};
getLoaderManager().initLoader(0x01, null, this);//null can be replaced by a Bundle of search criteria
adapter = new SimpleCursorAdapter(getActivity().getApplicationContext(), R.layout.list_item_results,
null, dbPlantColumns, fragPlantFields, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
if(adapter.isEmpty())//This returns true
Toast.makeText(getActivity().getApplicationContext(), "Nothing returned from the database",
Toast.LENGTH_LONG).show();
}// method: Activity.onCreate(Bundle)
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)){
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
}
}// method: ListFragment.onViewCreated(View, Bundle)
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
if (!(activity instanceof OnPlantSelectedListener)){
throw new IllegalStateException("Activity must implement fragment's listener.");
}
plantSelectedListener = (OnPlantSelectedListener) activity;
}// method: ListFragment.onAttach(Activity)
@Override
public void onDetach(){
super.onDetach();
plantSelectedListener = emptyPlantSelectedListener;
}// method: ListFragment.onDetach()
@Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
if (activatedPosition != ListView.INVALID_POSITION){
outState.putInt(STATE_ACTIVATED_POSITION, activatedPosition);
}
}// method: ListFragment.onSaveInstanceState(Bundle)
/* LoaderManager abstract methods */
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args){
//TODO parse args for searching. Second null is String[]; index 0-17 are search arguments.
String[] arguments = new String[18];
String[] dbPlantColumns = {DBContentProvider.TABLE_PLANT + "." + DBContentProvider.KEY_PLANT_ID,
DBContentProvider.KEY_FAMILY_TEXT, DBContentProvider.KEY_GENUS_TEXT, DBContentProvider.KEY_SPECIES,
DBContentProvider.KEY_COMMON_NAME_GROUP, DBContentProvider.KEY_GROWTH_FORM_TEXT};
CursorLoader cursorLoader = new CursorLoader(getActivity(), Uri.parse(DBContentProvider.CONTENT_URI_STRING +
"search"), dbPlantColumns, null, arguments, null);
return cursorLoader;
}// method: LoaderCallbacks.onCreateLoader(int, Bundle)
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor){
adapter.swapCursor(cursor);
}// method: LoaderCallbacks.onLoadFinished(Loader<Cursor>, Cursor)
@Override
public void onLoaderReset(Loader<Cursor> loader){
adapter.swapCursor(null);
}// method: LoaderCallbacks.onLoaderReset(Loader<Cursor>)
/* ListFragment response methods */
@Override
public void onListItemClick(ListView listView, View view, int position, long id){
super.onListItemClick(listView, view, position, id);
plantSelectedListener.onPlantSelected(id /*Get id of plant at this position*/);
}// method: ListFragment.onListItemClick(Listview, View, int, long)
public void setActivateOnItemClick(boolean activateOnItemClick){
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}// method: setActivateOnItemClick(boolean)
private void setActivatedPosition(int position){
if(position == ListView.INVALID_POSITION){
getListView().setItemChecked(activatedPosition, false);
}
else{
getListView().setItemChecked(position, true);
}
activatedPosition = position;
}//method: setActiviatedPosition(int)
/**
* OnPlantSelectedListener is used by the fragment and the activity to
* make sure that the selection of a plant is dealt with correctly.
*/
public interface OnPlantSelectedListener{
public void onPlantSelected(long id);
}// interface: OnPlantSelectedListener
}// class: ResultsFragment extends ListFragment
activity_results.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ResultsActivity"
android:id="@+id/Results_Lin"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- @android:id/list is the necessary id for the activity to find it. -->
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
</ListView>
<TextView
android:id="@+id/results_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/txt_no_results"/>
</LinearLayout>
fragment_results.xml
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="edu.dordt.grassrootsplantid.ResultsFragment"
android:id="@+id/Result_Fragment"/>
list_item_results.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/Result_Item_Lin"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<TextView
android:id="@+id/result_item_txt_lbl_common_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lbl_common_name"/>
<TextView
android:id="@+id/result_item_txt_common_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/result_item_txt_lbl_common_name"/>
<TextView
android:id="@+id/result_item_txt_lbl_scientific_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/result_item_txt_lbl_common_name"
android:text="@string/lbl_scientific_name"/>
<TextView
android:id="@+id/result_item_txt_genus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/result_item_txt_lbl_scientific_name"
android:layout_below="@id/result_item_txt_lbl_common_name"/>
<TextView
android:id="@+id/result_item_txt_species"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/result_item_txt_genus"
android:layout_below="@id/result_item_txt_lbl_common_name"
android:layout_marginLeft="5dp"/>
</RelativeLayout>
I probably misunderstand how to use fragments, but it was necessary in order to use the tutorial I was following for using Content Providers. I didn't put in the Content Provider here, but I'm pretty sure that's working (well...broken somewhere else, but I think I can handle that one). If someone wants to see it anyway, I can edit my question.
If it's at all relevant, the list items have their data and are clickable, but they appear greyed out as though they are unclickable. Perhaps that's a styling issue, but I would figure they would use the style shared by the rest of the app.
But to reiterate my problem, the listview is populating, but the adapter claims to be empty. I'm not sure how big of an issue it is/will be, but I would like either a way to get them to agree or an explanation of why they might not need to.
or an explanation of why they might not need to.
They seem not to agree because adapter is indeed empty at the time isEmpty
is called. Android's Loaders
do the work on a separate thread (asynchronously).
I suggest setting empty view instead of using toast.