Android Room - Избегайте передачи контекста в синглтон - PullRequest
0 голосов
/ 06 декабря 2018

Я пытаюсь перенести проект в Android Room.Прочитав документацию по Android Room, я заметил, что Singleton подходит для доступа к моей базе данных.

Цитата от разработчика Android:

Примечание. Если ваше приложение работает в одном процессе, выдолжен следовать шаблону одноэлементного проектирования при создании экземпляра объекта AppDatabase.Каждый экземпляр RoomDatabase довольно дорогой, и вам редко требуется доступ к нескольким экземплярам в рамках одного процесса.

Я написал следующий фрагмент кода:

@Database(entities = {Category.class, News.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {

    private static final String DB_NAME = "database.db";
    private static AppDatabase instance;

    public abstract CategoryDao categoryDao();
    public abstract NewsDao newsDao();

    private AppDatabase () {}

    public static AppDatabase getInstance(Context context) {
        if (instance == null) {
            synchronized (AppDatabase.class) {
                if (instance == null) {
                    instance = Room.databaseBuilder(context.getApplicationContext(),
                            AppDatabase.class, DB_NAME).build();
                }
            }
        }
        return instance;
    }
}

Просто двойнойпроверка блокировки синглтона.

Я прочитал несколько руководств / учебных пособий, и почти у всех есть подобный подход, однако я вижу некоторые проблемы с этим подходом:

  • Необходимо передать Context каждыйвремя, даже если вам нужен только один раз для инициализации Singleton.
  • Что если мне нужно получить доступ к базе данных без Context в наличии?
  • Даже допустимо отправлять параметры в Singleton?

Есть идеи, как реализовать Singleton Room Database, который решает эти проблемы?

Я хотел бы по возможности избегать библиотек DI, таких как Dagger2.

Ответы [ 3 ]

0 голосов
/ 10 декабря 2018
@Database(entities = {Category.class, News.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {

   private static final String DB_NAME = "database.db";
   private static AppDatabase instance;
   public abstract CategoryDao categoryDao();
   public abstract NewsDao newsDao();

   private AppDatabase () {}

   // Use this to call on any place
   public static AppDatabase getInstance(Context context) {
      return instance;
   }
   // Use once to Create and setup the object
   public static AppDatabase setInstance(Context context) {
      if (instance == null) {
         synchronized (AppDatabase.class) {
            if (instance == null) {
                instance = Room.databaseBuilder(context.getApplicationContext(),
                        AppDatabase.class, DB_NAME).build();
            }
        }
     }
     return instance;
   }
}

// Second you need to set instance on Application Class which create and make your DB 
  //Ready for Use Before anything perform
public class MyApplication extends Application {
   @Override
   public void onCreate() {
      super.onCreate();
      AppDatabase.setInstance(this)
   }
}

Для использования

//Need to call
AppDatabase.getInstance().categoryDao();
0 голосов
/ 21 июня 2019

Вы можете создать экземпляр БД, а затем заблокировать экземпляр.

Кроме того, вызов context.applicationContext возвращает контекст одного , глобального приложения объекта текущегопроцесс.Жизненный цикл этого контекста отделен от текущего context, который связан с временем жизни процесса, а не с текущим компонентом.

/**
 * The Room Database that contains the item table.
 */
@Database(entities = arrayOf(Item::class), version = 1, exportSchema = false)
abstract class ItemDb : RoomDatabase() {
    abstract fun itemDao(): ItemDao

    companion object {
        private var INSTANCE: ItemDb? = null

        private val lock = Any()

        @JvmStatic
        fun getInstance(context: Context): ItemDb {

            // When calling this instance concurrently from multiple threads we're in serious trouble:
            // So we use this method, 'synchronized' to lock the instance
            synchronized(lock) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.applicationContext, ItemDb::class.java, "items.db").build()
                }
                return INSTANCE!!
            }
        }
    }
}
0 голосов
/ 06 декабря 2018

Вы можете инициализировать свою базу данных и сохранить ее экземпляр в своем классе Application примерно так:

public class MyApplication extends Application {

    public AppDatabase database;

    @Override
    public void onCreate() {
        super.onCreate();

        database = AppDatabase.getInstance(this)
    }
}

Позднее вы можете получить доступ к своей ссылке, как

((MyApplication)activity).dabase

Надеюсь, что это будетпомощь.

...