5

I have a listfragment that displays a list from a database. I have everthing working correctly except for a small item that I can't seeem to clear up. The list view looks something like this.

-----------------------------------------------------
text text text | some more text | delete row button |
-----------------------------------------------------

My problem: when a user presses the delete row button the row is deleted from the database but will not be removed from the screen until the activity is stopped and started again.

I know that notifyDataSetChanged() is the preferred method for updating these lists but it does not seem to do anything... Anyhow, below is my code for the cursor adapter where notifyDataSetChanged() is called.

public class CalcCursorAdapter extends SimpleCursorAdapter{

    private Context mContext;
    private ListView mListView;
    private int mLayout;
    private Cursor mcursor;

    protected static class ViewHolder {
        protected TextView text;
        protected ImageButton button;
        private int position;
      }


    @SuppressWarnings("deprecation")
    public CalcCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) 
    {
        super(context, layout, c, from, to);
        this.mContext = context;
        this.mLayout = layout;
        this.mcursor = c;

        //mListView = .getListView();

    }       

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        TextView summary = (TextView)view.findViewById(R.id.calctvPrice);
        TextView savings = (TextView)view.findViewById(R.id.calctvSavings);
        TextView percentOff = (TextView)view.findViewById(R.id.calctvpercentOff);
        summary.setText(cursor.getString(cursor.getColumnIndexOrThrow("qcFinalPrice")));




    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        ViewHolder holder = new ViewHolder();

        LayoutInflater inflater = LayoutInflater.from(context);
        View v = inflater.inflate(R.layout.calc_list_item, parent, false);

        holder.button = (ImageButton) v.findViewById(R.id.qcbtnDelete);
        holder.button.setOnClickListener(deleteButton);
        holder.position = cursor.getInt(cursor.getColumnIndexOrThrow("_id"));
        bindView(v, context, cursor);
        v.setTag(holder);


        return v;

    }

    private OnClickListener deleteButton = new OnClickListener() {
        @SuppressWarnings("deprecation")
        public void onClick(View v){
            View view = (View) v.getParent();
            ViewHolder holder = (ViewHolder) view.getTag();
            int position = holder.position;
            DbHelper mDbHelper;
            mDbHelper = new DbHelper(mContext);
            mDbHelper.open();
            mDbHelper.deleteCalc(position);
            mDbHelper.close();
            String test = Integer.toString(position);
            Toast.makeText(mContext.getApplicationContext(), test, Toast.LENGTH_SHORT).show();  
            notifyDataSetChanged();



            //ListView list = getListView();


        }
    };

    public long qcItemId(int position) {

        return position;
    }




}

Thank you for your help.

UPDATE:

New button Code within my adapter:

private OnClickListener deleteButton = new OnClickListener() {
    @SuppressWarnings("deprecation")
    public void onClick(View v){
        v.invalidate();
        View view = (View) v.getParent();
        view.invalidate();
        ViewHolder holder = (ViewHolder) view.getTag();
        int position = holder.position;
        DbHelper mDbHelper;
        mDbHelper = new DbHelper(mContext);
        mDbHelper.open();
        mDbHelper.deleteCalc(position);
        mDbHelper.close();
        String test = Integer.toString(position);
        Toast.makeText(mContext.getApplicationContext(), test, Toast.LENGTH_SHORT).show();  
        Cursor newCursor = getCursor();
        changeCursor(newCursor);
        notifyDataSetChanged();



        //ListView list = getListView();


    }
};
richsage
  • 26,912
  • 8
  • 58
  • 65
Marek Counts
  • 126
  • 3
  • 11

1 Answers1

8

I got the same problem before, I don't think in this case notifyDataSetChanged alone can help you. What has changed is actually your cursor, so you need to reload it using the function changeCursor on your custom adapter. Here is an example:

changeCursor(yourCursor);
notifyDataSetChanged();

Here is the full code of how I managed this in my Fragment class:

ImageButton newCat = (ImageButton)categoriesListTitle.findViewById(R.id.new_category);

            newCat.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(final View v) {
                    categoriesDialog.dismiss();

                    AlertDialog.Builder newCatAlert = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), R.style.AlertDialogStyle));

                    newCatAlert.setTitle("New category");

                    // Set an EditText view to get user input 
                    final EditText newCatET = new EditText(v.getContext());
                    newCatAlert.setView(newCatET);

                    newCatAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            String newCatName = newCatET.getText().toString();

                            db.addCategory(newCatName);
                            mAdapter.changeCursor(db.getAllCategoriesByRate(currentRate));//Here I update the cursor used in my adapter
                            //In your case (you do not use a dialog), you have to add this line I think:
                            //mAdapter.notifyDataSetChanged();

                            categoriesDialog.show();
                        }

                    });

                    newCatAlert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            dialog.cancel();
                        }
                    });
                    newCatAlert.show();
                }
            });


            categoriesLV.setAdapter(mAdapter);
Yoann Hercouet
  • 17,894
  • 5
  • 58
  • 85
  • I added `Curser newCursor = getCursor(); changeCursor(newCursor);` after my database delete and this does nothing... it does not throw errors, it just does not do anything! Thanks for the help! – Marek Counts May 29 '13 at 00:56
  • I edited my answer, in my case I did not need to use `notifyDataSetChanged` because I was using a popup to display again the list, but for you it might be useful. Have it a try. – Yoann Hercouet May 29 '13 at 01:02
  • I have edited my main post to display better the code for my button within my adapter with these changes... I would like to verify that you know I'm working with a list fragment... not sure if that matters or not as this happens in the adapter and not the fragment. – Marek Counts May 29 '13 at 01:11
  • What does return your `getCursor` function? It should call again your DB to get an updated cursor. – Yoann Hercouet May 29 '13 at 01:21
  • I find this hard because I uses a loadermanager inside the fragment. And as hard as I have tried I have not been able to instigate the loader inside of the of the adapter... And because it is inside a fragment and the adapter is outside the fragment I have not been able to tell it to re-query... I'm sorry I'm not so good at this. – Marek Counts May 30 '13 at 00:27
  • You should I think call the `changeCursor` function in the Fragment, not in the Adapter. I updated my answer to show you a full event I manage in my own fragment to dynamically add a new category in a categories list. – Yoann Hercouet May 30 '13 at 06:35
  • I see what you did and I CAN update it from the fragment. The problem is because this button (delete button) is in every row I handle the click event inside the adapter (that way I can figure out what row was clicked). I would not mind passing this all to the fragment and letting it handle it but I'm not able to pass any infromation into a fragment from the adapter, that I know of... In the list fragment I have a public refreshlist function... but I can not call the fragment manager from a non-fragment. thank you for all your help and sorry if I'm missing something simple and stupid! – Marek Counts May 30 '13 at 17:06
  • OK so actually the problem is not the `notifyDataSetChanged` here, you have to move back your listener on your ListFragment class. Check these 3 links, maybe they explain why you got a problem the first time you tried: http://stackoverflow.com/questions/7274231/listfragment-onlistitemclick-not-being-called http://stackoverflow.com/questions/9690439/creating-custom-simple-cursor-adapter http://stackoverflow.com/questions/8611612/how-to-trigger-onlistitemclick-in-a-listfragment – Yoann Hercouet May 31 '13 at 07:26