Home > Software engineering >  How to automatically update ListView with custom adapter when item is deleted from database
How to automatically update ListView with custom adapter when item is deleted from database

Time:06-13

I created a ListView for which I implemented a custom adapter. Additionally I connected it to a SQLite database, which contains the content for the ListView.

I have one ListView with several items. Every item consists of a TextView and an ImageView which functions as a button. When the user clicks the ImageView, I want to delete the item from the database and automatically update the ListView.

Unluckily, I just know how to delete the item from the database. I can't think of a way to automatically update the ListView in my program, after the item got deleted from the database.

In the version below, I added an onItemClickListener for the ListView in the MainActivity - but it doesn't function for when the user clicks the ImageView (even though the ImageView is part of the ListView).

MainActivity

public class MainActivity extends AppCompatActivity {
//References to buttons and other controls on the layout
private Button btn_add;
private EditText et_todo;
private Switch sw;
private static ListView lv;
private static DataAdapter todoAdapter;
private DataBaseHelper dbHelper;

/**
 * Initialization Method
 *
 * @param savedInstanceState
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    dbHelper = new DataBaseHelper(MainActivity.this);

    assignVariables();
    registerClick();
    showAllToDos(dbHelper);
}

private void assignVariables() {
    //assign values to variables
    btn_add = (Button) findViewById(R.id.btn_add);
    et_todo = (EditText) findViewById(R.id.et_todo);
    lv = (ListView) findViewById(R.id.lv);
}

public void showAllToDos(DataBaseHelper dbHelper) {
    todoAdapter = new DataAdapter(MainActivity.this, R.layout.list_item, dbHelper.getAllAsList(), dbHelper);
    lv.setAdapter(todoAdapter);
}

private void registerClick() {
    btn_add.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String toDoTitle = et_todo.getText().toString();

            if(Pattern.matches("s*", toDoTitle)) {
                Toast.makeText(MainActivity.this, "Title is missing", Toast.LENGTH_SHORT).show();
            } else if(dbHelper.existsInDB(new DataModel(toDoTitle))) {
                Toast.makeText(MainActivity.this, "Already added as ToDo", Toast.LENGTH_SHORT).show();
            } else {
                DataModel dModel = new DataModel(toDoTitle);
                dbHelper.addOne(dModel);

                showAllToDos(dbHelper);
            }
            //empty input field
            et_todo.setText("");
        }
    });

    lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
            DataModel clickedItem = (DataModel) adapterView.getItemAtPosition(position);
            dbHelper.deleteOne(clickedItem);

            showAllToDos(dbHelper);
        }
    });
}

}

DataModel

public class DataModel {

//Attributes
private int id;
private String title;

//Constructors
public DataModel(String title) {
    this.title = title;
}

public DataModel() {

}

//toString
@Override
public String toString() {
    return "DataModel{"  
            "id="   id  
            ", title='"   title   '\''  
            '}';
}

//Getters and Setters
public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

}

DataAdapter

public class DataAdapter extends ArrayAdapter<DataModel> {

/**
 * Attributes
 */
private Context mContext;
private int mResource;
private ArrayList<DataModel> mList;
private DataBaseHelper mDbHelper;


public DataAdapter(Context context, int resource, ArrayList<DataModel> list, DataBaseHelper dbHelper) {
    super(context, resource, list);
    mContext = context;
    mResource = resource;
    mList = list;
    mDbHelper = dbHelper;
}

public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    //get the objects information
    String title = getItem(position).getTitle();

    //create object with the information
    DataModel model = new DataModel(title);

    LayoutInflater inflater = LayoutInflater.from(mContext);
    convertView = inflater.inflate(mResource, parent, false);

    //get TextViews
    TextView tvTitle = (TextView) convertView.findViewById(R.id.task);

    //set information to TextViews
    tvTitle.setText(title);

    //delete function
    ImageView delView = (ImageView) convertView.findViewById(R.id.delView);
    delView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mDbHelper.deleteOne(model);
        }
    });
    return convertView;
}

}

DataBaseHelper

public class DataBaseHelper extends SQLiteOpenHelper {

public static final String TODO_TABLE = "TODO_TABLE";
public static final String COLUMN_ID = "ID";
public static final String COLUMN_TODO_TITLE = "TODO_TITLE";
private Context mContext;

public DataBaseHelper(@Nullable Context context) {
    super(context, "todo.db", null, 1);
    mContext = context;
}

/**
 * Is called when the app requests or inputs new data.
 *
 * @param db
 */
@Override
public void onCreate(SQLiteDatabase db) {

    String createTableStatement = "CREATE TABLE "   TODO_TABLE
              " ("   COLUMN_ID   " INTEGER PRIMARY KEY AUTOINCREMENT,"
              COLUMN_TODO_TITLE   " TEXT)";

    db.execSQL(createTableStatement);
    //create new Table
}

/**
 * Called whenever the database version number changes.
 * Prevents the previous apps from crashing.
 *
 * @param sqLiteDatabase
 * @param i
 * @param i1
 */
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

}

/**
 * method to add new database entry
 *
 * @param dModel
 * @return
 */
public boolean addOne(DataModel dModel) {
    SQLiteDatabase db = this.getWritableDatabase(); //for insert actions
    ContentValues cv = new ContentValues(); //Content values stores data in pairs

    cv.put(COLUMN_TODO_TITLE, dModel.getTitle());

    long insert = db.insert(TODO_TABLE, null, cv);

    //clean up, close connection to database and cursor
    db.close();
    if(insert == -1) { //if insert is negative number than insert went wrong
        return false;
    } else { //if insert is positive number than insert succeeded
        return true;
    }
}

public boolean deleteOne(DataModel dModel) {
    //if DataModel is found in the database, delete it and return true
    //if it is not found, return false
    SQLiteDatabase db = this.getWritableDatabase();

    String queryString = "DELETE FROM "   TODO_TABLE
              " WHERE "   COLUMN_TODO_TITLE   " = "   "\""   dModel.getTitle()   "\"";;

    Cursor cursor = db.rawQuery(queryString, null);

    if(cursor.moveToFirst()) {
        return true;
    } else {
        return false;
    }
}

public ArrayList<DataModel> getAllAsList() {
    //create empty list
    ArrayList<DataModel> returnList = new ArrayList<>();
    //get data from the database
    String queryString = "SELECT * FROM "   TODO_TABLE;
    SQLiteDatabase db = this.getReadableDatabase(); //get data from database
    Cursor cursor = db.rawQuery(queryString, null);

    if(cursor.moveToFirst()) { //returns a true if there were items selected
        //loop through results, create new todo objects, put them into return list
        do {
            String todoTitle = cursor.getString(1);

            DataModel newTodo = new DataModel(todoTitle);
            returnList.add(newTodo);

        } while(cursor.moveToNext());
    } else { //returns a false if no items were selected
        //failure, to not add anything to the list
    }

    //clean up, close connection to database and cursor
    cursor.close();
    db.close();

    return returnList;
}

public boolean existsInDB(DataModel dModel) {
    SQLiteDatabase db = this.getWritableDatabase(); //for insert actions
    String queryString = "SELECT * FROM "   TODO_TABLE
              " WHERE "   COLUMN_TODO_TITLE   " = "   "\""   dModel.getTitle()   "\"";

    Cursor cursor = db.rawQuery(queryString, null);

    if(cursor.moveToFirst()) {
        return true;
    } else {
        return false;
    }
}

}

I appreciate any kind of help or suggestion. Let me know, if you need further explanation.

Nicole

CodePudding user response:

Using SQLite directly can be challenging, also ListView is outdated not recommended to use anymore. The best practise is to use RecycleView

Here is a good tutorial how enter image description here

  • Click on Item Test003 (NOT the purple box (image))

    1. Toast displays as expected.
    2. Log includes D/CLICKACTION: Item was clicked for TitleTest003
  • Click on the Delete image (purple box) for Test003

    1. Toast displays as expected Test003 position 2
    2. Log includes D/CLICKACTION: Image clicked for title = Test003 position 2
    3. enter image description here
      1. i.e. Test003 removed from the display
    4. Database via App Inspection shows:-
    • enter image description here
      • i.e. no Test003 row in the database
    • Related