0

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?

The 29th Saltshaker
  • 671
  • 1
  • 6
  • 16
  • 2
    you should also put your stacktrace here – Krupal Shah May 04 '16 at 16:47
  • I don't have a stacktrace because this crash only occurs when I have installed the app to my phone and left it alone for several hours. I can't replicate the error in my emulator / Android Studio (the only place where I am able to view the stacktrace / error logs as the errors are actually happening). – The 29th Saltshaker May 04 '16 at 16:49
  • 1
    You can send the crash report from your phone when it crashes I think. Try that? Upload it to the store in alpha testing mode, wait for it to crash and send the report. – Vucko May 04 '16 at 17:04
  • if you have root privilegs you can use the app catlog to show system logcat and your stacktrace will be displayed too – Ben May 04 '16 at 17:05
  • @Vucko I don't want to make the app public / I don't know how to upload it to the Store yet, let alone in Alpha mode – The 29th Saltshaker May 04 '16 at 17:05
  • @ChampS How do I get root privileges? – The 29th Saltshaker May 04 '16 at 17:06
  • @user54089 It will not be public if you upload it and set it to **closed** alpha/beta testing state. Only the people you give a permission and a link to, will be able to install it. – Vucko May 04 '16 at 17:08
  • How do I do all of that? – The 29th Saltshaker May 04 '16 at 17:09
  • how do you root your android device depends on your device. Google will give you the right answer. :) – Ben May 04 '16 at 17:27
  • 1
    use any crash reporting tool to intercept the error and send it to you. No need for either root or store publication – njzk2 May 04 '16 at 17:28
  • @njzk2 Such as what? – The 29th Saltshaker May 04 '16 at 17:35
  • @Vucko I've decided to try the store method. I just signed up for an account. If I go to Alpha Testing (what's the diff between Alpha and Beta here?), it says I need an APK. How do I correctly do this? – The 29th Saltshaker May 04 '16 at 17:53
  • fabric, splunk, flurry, ... there are plenty – njzk2 May 04 '16 at 17:56
  • Let me google that for you :D Well, you're gonna have to do it at one point anyway, right? So: In your Android studio under the **Build** menu, select **Generate signed APK** (you will need to google a bit about it tho). The difference between alpha and beta is not important (alpha for internal testing, beta for the people who hadn't made the app), since you can make both of them **closed**, which means your app is practically invisible to the outside world. – Vucko May 04 '16 at 18:25
  • Thankfully I did (and hopefully I understood the instructions). I generated the signed APK (although I have no idea what I was supposed to enter for most of the fields so I just winged it) and uploaded the APK to Closed Alpha testing and added my email under the testers. I uploaded random pics to satisfy the Publish criteria, generated a rating, filled out stuff, and now I clicked Publish and it's "processing update / pending publication." I hope I did all of this correctly? – The 29th Saltshaker May 04 '16 at 18:33

1 Answers1

0

This generally happens with singleton patterns in Android. You can read a bit about it here

Static singleton lifetime in Android

This has bitten me in the past. I would possibly move your open to the if statement in your getInstance method to run right after the database is created. That way if Android clear up the memory due to your app being idle over a long period of time it will also reopen the database when it is returned next. ie:

public static synchronized DatabaseHelper getInstance(Context context){
    if (mInstance == null){
        mInstance = new DatabaseHelper(context.getApplicationContext());
        try {
             mInstance.open();
        } catch (Exception exe) {}
    }
    return mInstance;
}
Community
  • 1
  • 1
Ira Juneau
  • 294
  • 1
  • 5