Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nullpointer Exception after deleting entry from SQL database

I'm working on an app for a robot where the user can define punch combinations which the robot will later fetch from the device. To allow the user to store these trainings I have defined a class "Trainings" which holds the id, the name and the punch combination of the training. This training is later saved in a database, for which I have written a DatabaseHandler class. Adding and displaying the data works fine, but whenever I want to delete an entry with the method below:

    public void deleteTraining(Training training) {
      SQLiteDatabase db = this.getWritableDatabase();

      db.delete(TABLE_TRAININGS, KEY_ID + " = ?",
      new String[] { String.valueOf(training.getID()) });
      db.close();
}

and later try to populate my GridView again ( handled by a GridAdapter class), I get a Nullpointer Exception

java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.noeth.tobi.mcrobektrainingsplaner.Training._name' on a null object reference
at com.noeth.tobi.mcrobektrainingsplaner.GridAdapter.getView(GridAdapter.java:50)

the getView method of the GridAdapter:

public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        // if it's not recycled, initialize some attributes
        btn = new Button(context);
        btn.setLayoutParams(new GridView.LayoutParams(370, 350));
        btn.setPadding(2,100,2,100);
        btn.setOnClickListener(new CustomOnClickListener(position, context));
        btn.setOnLongClickListener(new CustomOnLongClickListener(position, context, btn));

    }
    else {
        btn = (Button) convertView;
    }

    btn.setText(db.getTraining(position)._name); //Here the programm throws a Nullpointer Exception AFTER deleting an entry from the database

    btn.setTextColor(Color.WHITE);
    btn.setBackgroundResource(R.drawable.button_border);
    btn.setTag("not_activated");
    btn.setId(position);

    return btn;
}

I figured that it must have something to do with the id of the deleted training, as the loop simply goes through all ids so I wrote a method recalcIDs which recalculates the id of every item coming after the deleted training:
recalcIDs

public void recalcIDs(){
    int k = 1;
    int subtract = 1;
    int id;
    Training training;

    for(int i = deleted.get(0)+1; i < db.getTrainingCount(); i++){
        if(deleted.size() > 1){
            if(i < deleted.get(k)){
                training = db.getTraining(i);
                id = training.getID();
                training.setID(id-subtract);
            }
            else{
                k+=1;
                subtract+=1;
            }
        }
        else{
            training = db.getTraining(i);
            id = training.getID();
            training.setID(id-subtract);
        }


    }

} 

However this does not fix it.
When reinstalling the app and starting with a completely new database everythings works again.
Does anybody have an idea what I've done wrong?

P.S.: Here's the getTraining method where it can't find the name:

Training getTraining(int id) {
    SQLiteDatabase db = this.getReadableDatabase();
    Training training;
    Cursor cursor = db.query(TABLE_TRAININGS, new String[] { KEY_ID,
                    KEY_NAME, KEY_SK}, KEY_ID + "=?",
            new String[] { String.valueOf(id) }, null, null, null, null);
    if (cursor != null && cursor.moveToFirst()){

     training = new Training(Integer.parseInt(cursor.getString(0)),
            cursor.getString(1), cursor.getLong(2));
        cursor.close();
    }
    else{
        training = null;
        Toast.makeText(con,"Couldn't find any training sessions!", Toast.LENGTH_LONG).show();
    }

    // return training
    return training;
}
like image 400
Tobias Nöthlich Avatar asked Oct 29 '22 22:10

Tobias Nöthlich


1 Answers

I'm assuming your the Training.setId method doesn't call the database. You shouldn't change the id of your training because they get managed by the underlaying database. If you only change the ids in you application logic both datasets (application and database) will differ. I would recommend to reload all the trainings from the database after a user decided to delete one and call the Gridview.notifyDatasetChanged afterwards.

like image 52
Jacob Avatar answered Nov 09 '22 14:11

Jacob