1

I'm implementing an app with MVVM and Dagger.

I have a database as a singleton implementation provided with the scope of the application class.

@Database(entities = {Person.class, Notification.class}, version = 1, exportSchema = false)
@TypeConverters({DateConverter.class})
public abstract class MyDatabase extends RoomDatabase {

    private static final Object LOCK = new Object();
    private static final String DATABASE_NAME = Constants.DATABASE_NAME;

    private static MyDatabase sInstance;

    public static MyDatabase getInstance(final Context context) {

        if (sInstance == null) {

            synchronized (LOCK) {

                Log.d("Logger", "Get new DB instance");
               
                sInstance = Room.databaseBuilder(
                    context.getApplicationContext(),
                    MyDatabase .class,
                    MyDatabase.DATABASE_NAME)
                    .setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
                    .fallbackToDestructiveMigration()
                    .build();
            }
        }
        return sInstance;
    }
}

When I try to finish and restart my root activitiy, I can see that I don't get a new instance of my database. (There is no logcat output: "Get new DB instance")

I guess, that my app is not closed completely, some memory must still be allocated.

There are two options I found out:

1. Close the root activity by calling `System.exit(0)` and restart with startActivity(new Intent(this, MainActivity.class))`

2. Close the root activity by calling `finish()`, remove app from "recent app list" and the restart app manually

In this two cases I get a new instance of my database.

This is the way I do it now:

private void restartApplication() { 
   
    startActivity(new Intent(this, MainActivity.class));
    System.exit(0);
}

Is there a better way to restart my app without using System.exit(0)?

Background info:

In my app, I want to restore my database with a backup file programmatically. Therefore I need a new instance by calling Room.databaseBuilder(...).

Thanks in advance!

Chris P.

Chris P.
  • 41
  • 3
  • try to use provide and token management, explore this answer : https://stackoverflow.com/a/43147736/10954249 or you have to dispose component or recreate component – DeePanShu Sep 16 '21 at 10:45
  • Thanks for your answer! Now I have an idea to solve my problem by setting sInstance = null when root activity is destroyed. – Chris P. Sep 16 '21 at 11:09
  • ya, you can do on that way also, but token management is also a great Idea, if you want to try. – DeePanShu Sep 16 '21 at 11:55

1 Answers1

0

The problem is, that after finish() is called, the static data like sInstance will not get cleared.

Now I have an idea to solve my problem like this:

I changed the scope of my database instance

@Module
public abstract class AppModule {

    @Provides
    static Context provideContext(Application application) {

        return application;
    }

    //  @AppScope <-- Removed this scope which is the same as @Singleton
    @Provides
    static MyDatabase provideMyDatabase(Context context) {

        return MyDatabase.getInstance(context);
    }
}

And now when I finish my root activity, I set the sInstance = null

@Override
    protected void onDestroy() {

        MyDatabase.reset(); // This sets sInstance = null
        super.onDestroy();
    }

I think this is exactly I was looking for.

Chris P.
  • 41
  • 3