Search code examples
javaandroidsqliteandroid-cursoradapter

Remove more than one element from CursorAdapter/List View


I'm making a project in Android/Java. I have an activity with a listview that displays values from a database and a remove button. For the moment, each row of this list view consists of a checktextview. This last one displays the name of an element of the database. I want to select different elements (with the check text view) and then if I press the remove button, all the selected elements have to be removed from the list and from database. In the following I put the essential parts of my classes. I already done most of the work. This is my activity:

public class ShoppingListActivity extends AppCompatActivity {

// Variables for the management of the database
private DBManagerShoppingList dbShoppingList;
private Cursor crs;
// List view for the shopping list elements
private ListView shoppingListListView;
private ShoppingListViewAdapter shoppingListViewAdapter;
// Generic variables
private String selectedShoppingList;

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

    // Find of the useful widgets
    shoppingListListView = findViewById(R.id.listViewSelShoppingList);
    shoppingListsSpinner = findViewById(R.id.spinnerShoppingLists);
    selectedShoppingList = "List_1";
    populateListView();
}

// Populate list view from database
public void populateListView() {
    // Database management
    dbShoppingList = new DBManagerShoppingList(this, selectedShoppingList);
    crs = dbShoppingList.query();
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            shoppingListViewAdapter = new ShoppingListViewAdapter(ShoppingListActivity.this, crs, 0);
            shoppingListListView.setAdapter(shoppingListViewAdapter);
        }
    });
}

// Remove selected elements
public void removeSelectedElements(View btnRemove) {
    // TODO
}
}

This is my custom adapter:

public class ShoppingListViewAdapter extends CursorAdapter {

private LayoutInflater layoutInflater;
private List<Integer> elementsPosArrayList = new ArrayList<>();
private HashMap<String, Integer> elementsMap = new HashMap<>();

public ShoppingListViewAdapter(Context context, Cursor c, int flags) {
    super(context, c, flags);
    layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
    return layoutInflater.inflate(R.layout.list_view_row, viewGroup, false);
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
    // CheckBox management
    final CheckBox checkBoxElementName = view.findViewById(R.id.checkBoxElementName);
    String elementName = cursor.getString(cursor.getColumnIndex(DBFieldsShoppingList.FIELD_ELEMENT_NAME));
    checkBoxElementName.setText(elementName);
    elementsMap.put(elementName, cursor.getPosition());
    checkBoxElementName.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
            if (isChecked) {
                elementsPosArrayList.add(elementsMap.get(checkBoxElementName.getText().toString()));
            } else {
                elementsPosArrayList.remove(elementsMap.get(checkBoxElementName.getText().toString()));
            }
        }
    });
}

public long getElementId(Cursor crs, int position) {
    crs.moveToPosition(position);
    return crs.getLong(crs.getColumnIndex(DBFieldsShoppingList.FIELD_ID));
}

public List<Integer> getElementsPosArrayList() {
    return elementsPosArrayList;
}
}

Classes for the database management are the following: DBHelper:

public class DBHelperShoppingList extends SQLiteOpenHelper {

private String DBName;

public DBHelperShoppingList(@Nullable Context context, int dbVersion, String dbName) {
    super(context, dbName, null, dbVersion);
    this.DBName = dbName;
}

@Override
public void onCreate(SQLiteDatabase shoppingListDB) {
    String q = "CREATE TABLE " + DBFieldsShoppingList.FIELD_TABLE_NAME +
            " ( _id INTEGER PRIMARY KEY AUTOINCREMENT," +
            DBFieldsShoppingList.FIELD_ELEMENT_NAME + " TEXT," +
            DBFieldsShoppingList.FIELD_ELEMENT_TYPE + " TEXT," +
            DBFieldsShoppingList.FIELD_ELEMENT_QUANT + " TEXT)";
    shoppingListDB.execSQL(q);
}
@Override
public void onUpgrade(SQLiteDatabase shoppingListDB, int oldVersion, int newVersion) {}
}

Class for the fields of the database:

public class DBFieldsShoppingList {
    public static final String FIELD_ID = "_Id";
    public static final String FIELD_TABLE_NAME = "Shopping_List";
    public static final String FIELD_ELEMENT_NAME = "Element_Name";
    public static final String FIELD_ELEMENT_TYPE = "Element_Type";
    public static final String FIELD_ELEMENT_QUANT = "Element_Quant";
}

Class database manager:

public class DBManagerShoppingList {
private DBHelperShoppingList dbHelperShoppingList;

public DBManagerShoppingList(Context ctx, String shoppingListName) {
    dbHelperShoppingList = new DBHelperShoppingList(ctx, 1, shoppingListName);
}

public void dbSave(String elementName, String elementType, String elementQuantity) {
    SQLiteDatabase db = dbHelperShoppingList.getWritableDatabase();
    ContentValues cv = new ContentValues();
    cv.put(DBFieldsShoppingList.FIELD_ELEMENT_NAME, elementName);
    cv.put(DBFieldsShoppingList.FIELD_ELEMENT_TYPE, elementType);
    cv.put(DBFieldsShoppingList.FIELD_ELEMENT_QUANT, elementQuantity);
    try {
        db.insert(DBFieldsShoppingList.FIELD_TABLE_NAME, null, cv);
    } catch (SQLiteException ignored) {}
}

public boolean deleteElement(long id) {
    SQLiteDatabase db = dbHelperShoppingList.getWritableDatabase();
    try {
        return db.delete(DBFieldsShoppingList.FIELD_TABLE_NAME, DBFieldsShoppingList.FIELD_ID + "=?", new String[]{Long.toString(id)})>0;
    } catch(SQLiteException exc) {
        return false;
    }
}

public static void deleteDB(Context ctx, String DBName) {
    ctx.deleteDatabase(DBName);
}

public Cursor query() {
    Cursor crs;
    try {
        SQLiteDatabase db = dbHelperShoppingList.getReadableDatabase();
        crs = db.query(DBFieldsShoppingList.FIELD_TABLE_NAME, null, null, null, null, null, null, null);
    } catch (SQLiteException exc) {
        return null;
    }
    return crs;
}
}

I tought, in bindView method of the adapter class, to save a map between element name and its position. Then, to create a list of the element names of the checked elements. In this way, I can know the positions of the checked elements, from the map. Now, I have to get indexes of the checked elements, in order to remove them from database, with delete method of the database manager class. How can I solve this problem? If my structure is not correct, say me how to change. Thank you very much in advance.

Marco


Solution

  • Hy to everybody, I found the solution. In database manager class, I changed the delete method in the following way:

    public boolean deleteElement(String elementName) {
        SQLiteDatabase db = dbHelperShoppingList.getWritableDatabase();
        try {
            return db.delete(DBFieldsShoppingList.FIELD_TABLE_NAME, DBFieldsShoppingList.FIELD_ELEMENT_NAME + "=?", new String[]{(elementName)})>0;
        } catch(SQLiteException exc) {
            return false;
        }
    }
    

    This allows, to search by name in database. In adapter class, I removed the map, and I wrote an arraylist of string, where I put name of the checked elements:

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        // CheckBox management
        final CheckBox checkBoxElementName = view.findViewById(R.id.checkBoxElementName);
        String elementName = cursor.getString(cursor.getColumnIndex(DBFieldsShoppingList.FIELD_ELEMENT_NAME));
        checkBoxElementName.setText(elementName);
        checkBoxElementName.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
                if (isChecked) {
                    elementNamesArrayList.add(checkBoxElementName.getText().toString());
                } else {
                    elementNamesArrayList.remove(checkBoxElementName.getText().toString());
                }
            }
        });
    }
    

    Finally, in the activity class, the remove method is the following:

    public void removeSelectedElements(View btnRemove) {
        List<String> elementNamesArrayList = shoppingListViewAdapter.getElementNamesArrayList();
        for (String item: elementNamesArrayList) {
            dbShoppingList.deleteElement(item);
        }
        populateListView();
    }
    

    In this way I solved my problem.

    Marco