0

Android Studio keeps complaining ( lightbulb red X ) that 'db' and 'dbh' may not be instantiated in the finally block.

So three things:

  • If the insert fails, what is the state of dbh and db in the catch block, or the finally block?
  • More generally, what do I need to account for in the finally and catch blocks
  • Is lowering the complaint level in Android Studio the proper way to handle this :) ?

Below is the code. Its an Android AsyncTask.

    @Override
    protected Void doInBackground(Void... voids) {
        SweepDatabaseHelper dbh;
        SQLiteDatabase db;
        try{
            Random generator = new Random();
            float freqstep = (stopFreq - startFreq)/steps;

            dbh = new SweepDatabaseHelper(context);
            db = dbh.getWritableDatabase();

            // empty the table
            db.delete(dbh.TABLE_SWEEPDATA, null, null);
            // start writing the data
            for(int i=0;i<steps;i++){
                ContentValues values = new ContentValues();
                SweepData sdata=new SweepData( (long)i, startFreq+(i*freqstep), (float)generator.nextFloat()*10 );
                values.put(dbh.COLUMN_ID, (long)i);
                values.put(dbh.COLUMN_FREQ, startFreq+(i*freqstep));
                values.put(dbh.COLUMN_VSWR, sdata.getVswr());
                db.insert(dbh.TABLE_SWEEPDATA, null, values);
                publishProgress(new SweepData[]{sdata});
            }
            dbh.close();
            return null;
        }catch(Exception e){
            // Do nothing at the moment
            return null;
        }finally{
            if(db != null && dbh != null && db.isOpen()){
                db.close();
            }
        }

  }
lavajumper
  • 415
  • 3
  • 6
  • add at least a log and print the stacktrace in your catch block. otherwise someday something will silently crash and you'll spend hours looking for it. – njzk2 May 15 '15 at 21:40

2 Answers2

1

You need to either assign them an initial value at declaration time if they are defined in the method, or define them as instance variables.

The accepted answer to this question has a good explanation. Basically, instance variables will always have a default value, but that is not the case for local variables, that is why you are seeing the error.

You have two options to choose from to fix this.

The first option is to just initialize them to null:

SweepDatabaseHelper dbh = null;
SQLiteDatabase db = null;

I would recommend the second option of defining them as instance variables in your AsyncTask, and initialize in a constructor:

 SweepDatabaseHelper dbh; //make instance variable
 SQLiteDatabase db; //make instance variable

 //constructor
 public MyAsyncTask(Context context){

       dbh = new SweepDatabaseHelper(context);
       db = dbh.getWritableDatabase();
 }



 @Override
 protected Void doInBackground(Void... voids) {
        //SweepDatabaseHelper dbh; //remove
        //SQLiteDatabase db; //remove
        try{
            Random generator = new Random();
            float freqstep = (stopFreq - startFreq)/steps;

            //dbh = new SweepDatabaseHelper(context); //remove
            //db = dbh.getWritableDatabase(); //remove

            // empty the table
            db.delete(dbh.TABLE_SWEEPDATA, null, null);
            // start writing the data
            for(int i=0;i<steps;i++){
                ContentValues values = new ContentValues();
                SweepData sdata=new SweepData( (long)i, startFreq+(i*freqstep), (float)generator.nextFloat()*10 );
                values.put(dbh.COLUMN_ID, (long)i);
                values.put(dbh.COLUMN_FREQ, startFreq+(i*freqstep));
                values.put(dbh.COLUMN_VSWR, sdata.getVswr());
                db.insert(dbh.TABLE_SWEEPDATA, null, values);
                publishProgress(new SweepData[]{sdata});
            }
            dbh.close();
            return null;
        }catch(Exception e){
            // Do nothing at the moment
            return null;
        }finally{
            if(db != null && dbh != null && db.isOpen()){
                db.close();
            }
        }

  }
Community
  • 1
  • 1
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
0

You should be able to get Android Studio to stop complaining about this by simply initializing dbh and db to "null" when you define them.

SweepDatabaseHelper dbh = null;
SQLiteDatabase db = null;
try{
 ...
}catch{
    dbh = new SweepDatabaseHelper(context);
    db = dbh.getWritableDatabase();
}finally{
    ...
}

The reason is given in the Java specification:

4.12.5 Initial Values of Variables

...

A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16).

http://docs.oracle.com/javase/specs/jls/se7/jls7.pdf

So, for your three questions:

  • If the insert fails, what is the state of dbh and db in the catch block, or the finally block?

In your posted code, I would guess it won't compile.

  • More generally, what do I need to account for in the finally and catch blocks

You will want to put dbh.close() in your finally block so it always runs. Otherwise you may open the database, an exception occurs, and you end up leaving it opened.

You should use the catch block to take any action you'd want to do to if the operation fails, e.g., attempt error recovery, alert the user that there's a problem or ask them to make a decision, send an error report somewhere, etc.

  • Is lowering the complaint level in Android Studio the proper way to handle this :) ?

In some cases where you know exactly what you're doing, you know why it's complaining, and you know it's going to work, yes. In this case? No.

Community
  • 1
  • 1
ajpolt
  • 1,002
  • 6
  • 10
  • I see your point. One issue I had was that the code compiled and ran, so I was a bit baffled why Android Studio was complaining so loudly. – lavajumper May 15 '15 at 21:35