androidlistviewandroid-listview

Delete an item from Array List contact to Custom List View always delteing the latest one


I have a custom list view, contains delete button and spinner (the spinner contain A-E characters). And I have an issue with deleting the true row from my custom list view.

Custom list view code:

public class customListView extends BaseAdapter
{
    public Activity context;
    ArrayList<MyActivity.UserProperties> userPropertieses;
    public String[] spinnerValues;
    public LayoutInflater inflater;

    public  customListView(Activity context, ArrayList<MyActivity.UserProperties> userPropertieses, String[] spinnerArray)
    {
        super();
        this.context = context;
        this.userPropertieses = userPropertieses;
        spinnerValues = spinnerArray;
        this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() { return userPropertieses.size(); }

    @Override
    public Object getItem(int i) { return null; }

    @Override
    public long getItemId(int i) { return 0; }

    class ViewHolder
    {
        Button btnRemove;
        Spinner spinner;
    }

    @Override
    public View getView(final int i, View view, ViewGroup viewGroup)
    {
        final ViewHolder holder;
        if (view == null)
        {
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.custom_layout, null);

            holder.spinner = (Spinner) view.findViewById(R.id.spinner);
            holder.btnRemove = (Button) view.findViewById(R.id.bu_Remove);

            // populate spinner
            ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>
                    (view.getContext(), android.R.layout.simple_spinner_item, spinnerValues);
            dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            holder.spinner.setFocusable(true);
            holder.spinner.requestFocus();
            holder.spinner.setAdapter(dataAdapter);

            view.setTag(holder);

            // remove user implementation
            holder.btnRemove.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.i("custom list view debug", "i = " + i);  // debug. verify i value is correct
                    ((MyActivity) context).deleteUser(i);
                }
            });

        }
        else
            holder = (ViewHolder) view.getTag();

        return view;
    }
}

And my main activity code looks like this:

public class MyActivity extends Activity
{
    ListView listView;
    ArrayList<UserProperties> userProperties = new ArrayList<UserProperties>();
    customListView adapter;
    SensorManager sensorManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

        for (int i = 0; i<5; i++) {
            userProperties.add(new UserProperties());
        }

        listView = (ListView) findViewById(R.id.listView);
        String[] spinnerValues = new String[] {"A", "B", "C", "D", "E"};
        adapter = new customListView(MyActivity.this, userProperties, spinnerValues);
        listView.setAdapter(adapter);
    }

    public void deleteUser (int index)
    {
        Log.i("debug", "Removing item " + index); // the index is really true and the true node deleting from the ArrayList but somehow the latest delete from the UI
        userProperties.remove(index);
        adapter.notifyDataSetChanged();
    }
}

When I click on the Remove button deleteUser method called with the right index. but although the right node deleting from userProperties ArrayList somehow after notiftDataSetChanged is still alive and the latest node delete.

So, how can I delete the right node/row (from the ArrayList and UI...)

EDIT: Just to be clear, i variable contain true index. The true node deleted from the ArrayList. but something append after I called notify method. I prefer to stay with BaseAdapter and not implement ArrayAdapter.

EDIT 2: After more debugging I found out my question was wrong. the true row really deleted just spinner values somehow update their values. I cannot close the question because it already answered.


Solution

  • ((MyActivity) context).deleteUser(i);
    

    This line will always delete the first value from the ListView

    You can use CAB (contextual action bar)

    See if the code helps you(it's basically a ListActivity with a custom adapter to hold the status of checked items(+ different background)):

    public class CABSelection extends ListActivity {
    
        private ArrayList<String> mItems = new ArrayList<String>();
        private SelectionAdapter mAdapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            for (int i = 0; i < 24; i++) {
                mItems.add("Name" + i);
            }
            // R.layout.adapters_cabselection_row is a LinearLayout(with green
            // background(#99cc00)) that wraps an ImageView and a TextView
            mAdapter = new SelectionAdapter(this,
                    R.layout.adapters_cabselection_row, R.id.the_text, mItems);
            setListAdapter(mAdapter);
            getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
            getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
    
                private int nr = 0;
    
                @Override
                public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                    MenuInflater inflater = getMenuInflater();
                    inflater.inflate(R.menu.cabselection_menu, menu);
                    return true;
                }
    
                @Override
                public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                    return false;
                }
    
                @Override
                public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                    StringBuilder sb = new StringBuilder();
                    Set<Integer> positions = mAdapter.getCurrentCheckedPosition();
                    for (Integer pos : positions) {
                        sb.append(" " + pos + ",");
                    }               
                    switch (item.getItemId()) {
                    case R.id.edit_entry:
                        Toast.makeText(CABSelection.this, "Edited entries: " + sb.toString(),
                                Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.delete_entry:
                        Toast.makeText(CABSelection.this, "Deleted entries : " + sb.toString(),
                                Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.finish_it:
                        nr = 0;
                        mAdapter.clearSelection();
                        Toast.makeText(CABSelection.this, "Finish the CAB!",
                                Toast.LENGTH_SHORT).show();
                        mode.finish();
                    }
                    return false;
                }
    
                @Override
                public void onDestroyActionMode(ActionMode mode) {
                    nr = 0;
                    mAdapter.clearSelection();
                }
    
                @Override
                public void onItemCheckedStateChanged(ActionMode mode,
                        int position, long id, boolean checked) {
                    if (checked) {
                        nr++;
                        mAdapter.setNewSelection(position, checked);                    
                    } else {
                        nr--;
                        mAdapter.removeSelection(position);                 
                    }
                    mode.setTitle(nr + " rows selected!");
    
                }
    
            });
        }
    
        @Override
        protected void onListItemClick(ListView l, View v, int position, long id) {
            l.setItemChecked(position, !mAdapter.isPositionChecked(position));
        }
    
        private class SelectionAdapter extends ArrayAdapter<String> {
    
            private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
    
            public SelectionAdapter(Context context, int resource,
                    int textViewResourceId, List<String> objects) {
                super(context, resource, textViewResourceId, objects);
            }
    
            public void setNewSelection(int position, boolean value) {
                mSelection.put(position, value);
                notifyDataSetChanged();
            }
    
            public boolean isPositionChecked(int position) {
                Boolean result = mSelection.get(position);
                return result == null ? false : result;
            }
    
            public Set<Integer> getCurrentCheckedPosition() {
                return mSelection.keySet();
            }
    
            public void removeSelection(int position) {
                mSelection.remove(position);
                notifyDataSetChanged();
            }
    
            public void clearSelection() {
                mSelection = new HashMap<Integer, Boolean>();
                notifyDataSetChanged();
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View v = super.getView(position, convertView, parent);//let the adapter handle setting up the row views
                v.setBackgroundColor(Color.parseColor("#99cc00")); //default color
                if (mSelection.get(position) != null) {
                    v.setBackgroundColor(Color.RED);// this is a selected position so make it red
                }
                return v;
            }
    
        }
    
    }