我正在尝试将项目迁移到Android Room。阅读Android Room文档后,我发现Singleton适合访问我的数据库。
Android Developer的报价:
注意:如果您的应用程序在单个进程中运行,则在实例化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;
}
}
一个简单的双重检查锁定Singleton。
我已经阅读了一些指南/教程,几乎每个人都采用了类似的方法,但是我看到这种方法存在一些问题:
Context
即可初始化Singleton。Context
的情况下访问数据库怎么办?有什么想法可以实现解决这些问题的Room Database Singleton?
如果可能,我想避免使用Dagger2之类的DI库。
答案 0 :(得分:1)
您可以初始化数据库并将其实例保存到Application类中。
public class MyApplication extends Application {
public AppDatabase database;
@Override
public void onCreate() {
super.onCreate();
database = AppDatabase.getInstance(this)
}
}
您可以像
一样访问您的参考资料((MyApplication)activity).dabase
希望这会有所帮助。
答案 1 :(得分:0)
@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();
答案 2 :(得分:0)
您可以实例化数据库,然后锁定实例。
此外,调用context.applicationContext
返回当前进程的单个,全局Application 对象的上下文。此Context的生命周期与当前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!!
}
}
}
}
答案 3 :(得分:0)
这里有很多事情要考虑。这完全取决于您的用例-因为您可能需要让您的应用仅在单线程上触摸数据库,所以您根本不需要在那里进行任何同步。
但是,如果您需要一些补充解决方案(在上述情况下也可能称其为“过大杀伤力”),请选中此处粘贴的https://github.com/android/architecture-components-samples仅供参考(有关此方法的讨论是here :
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.observability.persistence
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context
/**
* The Room database that contains the Users table
*/
@Database(entities = [User::class], version = 1)
abstract class UsersDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
@Volatile private var INSTANCE: UsersDatabase? = null
fun getInstance(context: Context): UsersDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(context.applicationContext,
UsersDatabase::class.java, "Sample.db")
.build()
}
}
通常-您可能想看看Kotlin double checking singleton和/或Java Double-Checked Locking with Singleton。
答案 4 :(得分:0)
你可以使用这个功能
public class DatabaseClient {
private Context mCtx;
private static DatabaseClient mInstance;
//our app database object
private final AppDatabase appDatabase;
private DatabaseClient(Context mCtx) {
this.mCtx = mCtx;
//creating the app database with Room database builder
//alldata is the name of the database
appDatabase = Room.databaseBuilder(mCtx, AppDatabase.class, "alldata").build();
}
public static synchronized DatabaseClient getInstance(Context mCtx) {
if (mInstance == null) {
mInstance = new DatabaseClient(mCtx);
}
return mInstance;
}
public AppDatabase getAppDatabase() { return appDatabase; }
}
并使用它来调用 getInstance()
DatabaseClient.getInstance(MainActivity.this).getAppDatabase().memberDao();
AppDatabase 类如下所示:
@Database(entities = {Member.class} , version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
public abstract MemberDao memberDao();
}