mercredi 4 mai 2016

Is my app crashing because I've mis-implemented my database singleton?

So my app seems to work just fine as long as I'm actively using the phone. I can rotate the screen, close the app, re-open it, whatever, no issues.

But if I press the home/back button and send the app to the background, and then if I go to bed for the night, when I wake up several hours later and try to open the app again, it crashes immediately. I have no idea what's causing this error but I assume it has to do with a NullPointerException (the bane of my existence at this point) because Android has decided to free up something for memory.

I consulted this diagram:

enter image description here

So when I send the app to the background, it goes to onStop(), and then Android may eventually free up some memory and kill the process, so when I open the app again, it tries to invoke onCreate(), except now onCreate() crashes. This made no sense to me.

The only other reason I could come up with was the fact that I use an SQLite3 database singleton in my app that is somehow getting eaten up by Android freeing up memory. In the onCreate() method of all my Activities and Fragments I typically call mDatabaseHelper = DatabaseHelper.getInstance(context); (where the context is usually either this if I'm in an Activity, or getActivity() if I'm in a Fragment).

This is my DatabaseHelper class:

public class DatabaseHelper extends SQLiteOpenHelper {
    private static volatile SQLiteDatabase mDatabase;
    private static DatabaseHelper mInstance = null;
    private static Context mContext;

    //... various constant fields here ...

    public static synchronized DatabaseHelper getInstance(Context context){
        if (mInstance == null){
            mInstance = new DatabaseHelper(context.getApplicationContext());
        }
        return mInstance;
    }

    private DatabaseHelper(Context context){
        super(context, DB_NAME, null, DB_VERSION);
        mContext = context;
    }

    public void open() throws SQLException {
        mDatabase = getWritableDatabase();
    }

    public void close(){
        mDatabase.close();
    }

    //... other functions here ...
}

In my launcher activity (MainActivity), I do this:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DatabaseHelper databaseHelper = DatabaseHelper.getInstance(this);
        databaseHelper.open(); 
        Intent intent = new Intent(this, AnotherActivity.class);
        startActivity(intent);
        finish();
    }

}

This is the only time I ever call open() in the entire app. I never call close() anywhere.

Does this explain what's causing my app to crash? Since I call getInstance() in my onCreate methods (which get called when I resume the app after a long idle period), this leads me to suspect that something is going wrong in that function. Can Android ever free up memory by somehow destroying the "Application context"? Is it possible that mDatabase is somehow getting set to null? What more do I need to do to ensure I have implemented this Database properly?

Aucun commentaire:

Enregistrer un commentaire