Enabling an onListItemClick in a ListFragment - android

I have a ListFragment that is being called from a Tab Navigation in an ActionBar. I have a custom adapter to display two different textviews for each list item. I'm having trouble implementing my onItemClickListener. Here is my ListFragment code:
public class MaterialsListFragment extends SherlockListFragment {
public ERGAdapter db;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.portrait_material_view, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// create new DBAdapter
db = new ERGAdapter(getActivity());
// ---- get all records
db.open(); // Open database
// Get all of the notes from the database and create the item list
Cursor c = db.getAllRecords();
String[] from = new String[] { ERGAdapter.KEY_IDNO, ERGAdapter.KEY_MATERIAL };
int[] to = new int[] { R.id.idno, R.id.materials };
// Now create an array adapter and set it to display using our row
MyListAdapter materials = new MyListAdapter(getActivity(), R.layout.list_cell, c, from, to);
setListAdapter(materials);
// get the list view and the set the listener
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Log.i("MATERIAL"," - position: "+Integer.toString(position));
}
});
}
public class MyListAdapter extends SimpleCursorAdapter {
public MyListAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to) {
super(context, layout , cursor, from, to);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Create the idno textview with background image
TextView idno = (TextView) view.findViewById(R.id.idno);
String unidno = String.format("%1$.0f", cursor.getDouble(3));
idno.setText(unidno);
// create the material textview
TextView materials = (TextView) view.findViewById(R.id.materials);
materials.setText(cursor.getString(1));
}
}
}
I'm getting a fatal exception with this line: ListView lv = getListView();
Here is the pertinent logcat:
05-25 16:32:45.802: E/AndroidRuntime(660): Caused by: java.lang.IllegalStateException: Content view not yet created
05-25 16:32:45.802: E/AndroidRuntime(660): at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
05-25 16:32:45.802: E/AndroidRuntime(660): at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
05-25 16:32:45.802: E/AndroidRuntime(660): at com.cca.ergpro.MaterialsListFragment.onCreate(MaterialsListFragment.java:80)
I think that I need to make it part of my custom CursorAdapter, but I'm not sure how to proceed. Any suggestions would be greatly appreciated.

I was able to get it working using the solution from this question:
Creating custom simple cursor adapter

Related

Checkbox losing state on scroll using cursorAdapter

I'm currently working on a simple Android application which will allow a user to add/remove/delete a record from a sqlite DB using checkboxes.
The main activity has a listview which renders objects from an exercise adapter. The adapter extends from cursor adapter.
The issue I'm having is when selecting a checkbox, then scrolling down the list so that the checkbox is out of view, the state is lost.
Here are extracts of my main activity and my exercise adapter:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbManager = new DBManager(this);
dbManager.open();
adapter = new ExerciseAdapter(this, dbManager.fetch());
listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter);
}
public void deleteExercise(View view) {
for (int i = 0; i < adapter.getCount(); i++) {
CheckBox c = listView.getChildAt(i).findViewById(R.id.checkBox);
if (c.isChecked()) {
deleteIds.add(adapter.getItemId(i));
}
}
for (Long deleteId : deleteIds) {
dbManager.delete(deleteId);
adapter.update(dbManager.fetch());
}
}
ExerciseAdapter:
public class ExerciseAdapter extends CursorAdapter {
public ExerciseAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.exercise, parent, false);}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView exerciseTitle = view.findViewById(R.id.exerciseTitle);
TextView exerciseDesc = view.findViewById(R.id.exerciseDescription);
TextView exerciseDate = view.findViewById(R.id.exerciseDate);
// Extract properties from cursor
String title = cursor.getString(cursor.getColumnIndexOrThrow("title"));
String desc = cursor.getString(cursor.getColumnIndexOrThrow("description"));
String date = cursor.getString(cursor.getColumnIndexOrThrow("date"));
// Populate fields with extracted properties
exerciseTitle.setText(title);
exerciseDesc.setText(String.valueOf(desc));
exerciseDate.setText(String.valueOf(date));
}
public void update(Cursor cursor) {
this.swapCursor(cursor);
this.notifyDataSetChanged();
}
}
This is adopted code so would like to keep the classes similar to how they are now, unless there is no other option and a big change is required.
Thanks.

Where do I use notifydatasetchanged in my code? Need for my ListView to automatically update itself after list item deletion

I know this has been discussed extensively on StackOverflow, and on the internet in general, but I can't find any good, solid information that helps me with my situation. At least none that I can understand and translate for my situation.
I have data in the database that I am retrieving with a Cursor. I am sticking this data into a ListView within a Fragment. On each line of my list, there is a button I use to delete that item. This all works, but I cannot figure out how to use notifydatasetchanged so that the ListView automatically refreshes itself, and the user can see that the deletion took place.
I have the List embedded in a SwipeRefreshLayout and the list item does disappear when I swipe it after deletion. However, what I want is for the list to automatically update on its own, which is what I thought the notifydatasetchanged was supposed to provide. Is this not the case? Is my understanding of notifydatasetchanged 100% incorrect?
Anyway, here is what I have:
My Home.java fragment:
public class Home extends Fragment{
private MainActivity mainActivity;
private View rootView;
private SwipeRefreshLayout personSwipeRefresh;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
rootView = inflater.inflate(R.layout.home, container, false);
personSwipeRefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.person_swipe_refresh);
mainActivity = (MainActivity)getActivity();
return rootView;
}
#Override
public void onViewCreated(View rootView, Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
drawThePersonView();
personSwipeRefresh.setColorSchemeColors(Color.parseColor(Constants.RED), Color.parseColor(Constants.ORANGE), Color.parseColor(Constants.YELLOW), Color.parseColor(Constants.GREEN), Color.parseColor(Constants.BLUE), Color.parseColor(Constants.INDIGO), Color.parseColor(Constants.VIOLET));
personSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
personSwipeRefresh.setRefreshing(false);
drawThePersonView();
}
});
}
#Override
public void onResume() {
super.onResume();
drawThePersonView();
}
public void drawThePersonView(){
Context context = getContext();
DatabaseHelper myDBHelper = new DatabaseHelper(context);
Cursor personCursor = myDBHelper.getPersonCursor();
String[] fromColumns = {"_id","personNumber","location","status"};
int[] toViews = {R.id.person_number_textview, R.id.personNumber_textview, R.id.person_location_textview, R.id.person_status_textview};
CustomSimpleCursorAdapter mySimpleCursorAdapter = new CustomSimpleCursorAdapter(context, R.layout.person_layout, personCursor, fromColumns, toViews, 0, mainActivity);
ListView myListView = (ListView) rootView.findViewById(R.id.person_row);
// Draw the list
myListView.setAdapter(mySimpleCursorAdapter);
myDBHelper.close();
}
}
My CustomSimpleCursorAdapter.java
public class CustomSimpleCursorAdapter extends SimpleCursorAdapter {
private Context context;
public CustomSimpleCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int flags) {
super(context, layout, cursor, from, to, flags);
this.context = context;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent){
DatabaseHelper dbHelper = new DatabaseHelper(context);
View row = super.getView(position, convertView, parent);
cursor.moveToPosition(position);
final Integer ID = cursor.getInt(cursor.getColumnIndex("_id"));
final String PERSON_NUMBER = cursor.getString(cursor.getColumnIndex("personNumber"));
// Make the delete button clickable.
Button deletePersonButton = (Button)row.findViewById(R.id.remove_person);
deletePersonButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DatabaseHelper databaseHelper = new DatabaseHelper(context);
databaseHelper.deletePerson(PERSON_NUMBER);
}
});
return row;
}
}
Here is something I did try that I thought would work, but it did not:
Button deletePersonButton = (Button)row.findViewById(R.id.remove_person);
final CustomSimpleCursorAdapter csca = (CustomSimpleCursorAdapter)this;
...
databaseHelper.deletePerson(PERSON_NUMBER);
csca.notifydatasetchanged();
Thank you for taking the time to read this.
Have a good day. :-)
UPDATE: I found out my issue is that my cursor does not refresh when I delete from the database. If I had 5 items in the list before deletion, the cursor.getCount() says 5, but after I delete the item from the database, the `cursor.getCount()`` still says 5. How do I get my cursor to refresh from within my custom SimpleCursorAdapter?

ListActivity ListView completed load

I want to set the background color depending on the data for the row of the ListView. I implemented a ListActivity but I dont know how to get notified the load is completed so that I can access the rows of the ListView.
public class RouteList extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.route_list);
CommuteDb db = new CommuteDb(this);
Cursor cursor = db.getRouteList();
ListAdapter adapter = new SimpleCursorAdapter(this, // Context.
R.layout.route_row, //row template
cursor, // Pass in the cursor to bind to.
new String[] { BaseColumns._ID, "Name" }, //Columns from table
new int[] { R.id.id, R.id.name }, //View to display data
0); //FLAG_REGISTER_CONTENT_OBSERVER
setListAdapter(adapter);
ListView listView = (ListView) findViewById(android.R.id.list);
Log.i("RouteList","listView.getChildCount()=" + listView.getChildCount()); //returns always 0
//Loop will not execute because no row yet
for (int i=0; i < listView.getChildCount(); i++) {
View rowView = listView.getChildAt(i);
Log.i("RouteList",rowView.getClass().getName());
rowView.setBackgroundColor(0x88ff0000);
}
If I execute this loop later (for instance on user's request) I am able to get each row and assign the color I want. However I need to do this automatically after data are loaded in ListView.
Thanx for the hint guys.
It works after modifying the code this way:
I added a custom adapter (RouteAdapter) derived from SimpleCursorAdapter:
private class RouteAdapter extends SimpleCursorAdapter {
public RouteAdapter(Context context, int layout, Cursor c,
String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//Let the default getView do the job (inflate the row layout and set views to their values from database
View view = super.getView(position, convertView, parent);
//Get the resulting view (route_row) and do custom loading
TextView isOffer = (TextView) view.findViewById(R.id.isOffer);
if (isOffer.getText().equals("0"))
view.setBackgroundColor(0x8800ff00); //seek=green
else
view.setBackgroundColor(0x88ff0000); //offer=red
return view;
}
}
Then in my original code I just replaced SimpleCursorAdapter by RouteAdapter:
ListAdapter adapter = new RouteAdapter(this, // Context.

Cannot display image on listview using simple cursor adapter

I had populated a listview using simplecursoradapter. However, I want to add images, wherein if the answer is correct it should display check on the right and if null or incorrect it should display an x-mark. It does not display anything but there is no error. Here is my activity code:
public class Results extends ListActivity{
DBAdapter db = new DBAdapter(this);
private Cursor mCursor;
ImageView iv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.resultslist);
db.open();
fillData();
db.close();
}
private void fillData() {
mCursor = db.getAllInfo();
startManagingCursor(mCursor);
String[] from = new String[]{DBAdapter.KEY_QUESTIONS, DBAdapter.KEY_CORRECTANSWERS, DBAdapter.KEY_YOURANSWERS};
int[] to = new int[]{R.id.textViewquestionresults, R.id.textViewcorrectansresults, R.id.textViewyouranswerresults};
SimpleCursorAdapter c=
new SimpleCursorAdapter(this, R.layout.rowresults, mCursor, from, to);
setListAdapter(c);
}
private class c extends SimpleCursorAdapter{
Context lcontext;
public c(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
lcontext = context;
}
#Override
public View getView(final int pos, View v, ViewGroup parent) {
v = super.getView(pos, v, parent);
final ImageView iv = (ImageView) v.findViewById(R.id.imageViewresults);
final TextView tvQuestion = (TextView) v.findViewById(R.id.textViewQuestion);
final TextView tvCorrectAns = (TextView) v.findViewById(R.id.textViewcorrectansresults);
final TextView tvYourAns = (TextView) v.findViewById(R.id.textViewyouranswerresults);
if(tvYourAns.equals(tvCorrectAns)){
iv.setImageResource(R.drawable.greencheckmark);
}else{
iv.setImageResource(R.drawable.redxmark);
}
return v;
}
}
}
When extending SimpleCursorAdapter, you shouldn't override getView().
You should override newView() and bindView() instead.
In newView() inflate your layout and initialize your views.
In bindView() set your views' values.

Android design using ListFragment with SQLite database

What is the best way to implement a ListFragment using SQLite database. Currently I have created an DBAdapter to facilitate opening, closing, and fetching records into a SimpleCursorAdapter. I have my MainActivity which implements an ActionBar with Navigation Tabs which I would like to display a different ListView for each tab.
Here is my ListFragment:
public class MaterialsListFragment extends ListFragment {
public DBAdapter db;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.portrait_material_view, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// create new DBAdapter
db = new DBAdapter(getActivity());
db.open();
Cursor c = db.getAllRecords();
String[] from = new String[] { DBAdapter.KEY_IDNO, DBAdapter.KEY_MATERIAL };
int[] to = new int[] { R.id.idno, R.id.materials };
// Now create an array adapter and set it to display using our row
MyListAdapter materials = new MyListAdapter(this, R.layout.list_cell, c, from, to);
setListAdapter(materials);
}
Here is MyListAdapter code which for now is in it's own class file:
public class MyListAdapter extends SimpleCursorAdapter {
public MyListAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to) {
super(context, layout , cursor, from, to);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Create the idno textview with background image
TextView idno = (TextView) view.findViewById(R.id.idno);
idno.setText(cursor.getSring(3));
// create the material textview
TextView materials = (TextView) view.findViewById(R.id.materials);
materials.setText(cursor.getString(1));
}
}
Is this the way to go about this? I would appreciate any suggestion you may have or if you know of any good examples.
I was able to get this to work, so I think I'm on the right track. I had to make this modification to get it to run, but it seems to be working well.
MyListAdapter materials = new MyListAdapter(getActivity(), R.layout.list_cell, c, from, to);
I would still be interested in any suggestions or ways to improve this approach.

Categories

Resources