Room(Android Jetpack)でデータベースを構築した場合、アプリのパフォーマンスを考えると、識別子の共有が必要になってきます。
この点について、まとめました。
※環境:Android Studio Ladybug | 2024.2.1 Patch 3
Kotlin 2.0.0
androidx.sqlite:sqlite:2.4.0
androidx.room:room-*:2.6.1
※サンプルの全体像は「Roomでデータベースを構築」を参照
識別子の共有
データベースのアクセスを開始する前に、データベースと接続の確立(Open)を行います。
データベース識別子は、その結果として得られるものです。
この接続の確立ですが、非常にコスト(処理時間、CPUの能力消費、メモリー消費)の大きい処理です。ドキュメントにそのような説明があります。
ですので、アプリケーション全体のパフォーマンスを考えると、極力、回数を減らす実装が必要となります。
その方法は2つです。
- ・識別子のシングルトン化
- ・識別子をコンポーネント間で共有
シングルトン化
RoomDatabaseクラスを継承した子クラス(GameDb)に実装した#getDatabase()はファクトリーメソッドです。
初回の#getDatabase()でビルドした自身のインスタンスを、結果として返すと共に、静的な変数instanceへ自己保持します。
2回目以降の#getDatabase()は、変数instanceからインスタンスを返し、ビルドは行われません。
ですので、#getDatabase()で返されるインスタンスはシングルトンになります。
@Database(entities = arrayOf(Player::class), version = 1)
abstract class GameDb : RoomDatabase() {
abstract fun playerDao(): PlayerDao
companion object {
@Volatile
private var instance: GameDb? = null
fun getDatabase(context: Context): GameDb {
return instance ?: synchronized(this) {
val _instans = Room.databaseBuilder(
context,
GameDb::class.java,
"Game.db"
)
.build()
instance = _instans // 自己保持
_instans // 結果として返す
}
}
}
}
コンポーネント間で共有
Applicationクラスを使って、RoomDatabase(GameDb)インスタンスの共有を行います。
※Applicatinについては「アプリ全体から参照可能なインスタンス(Application)」を参照
class MyApplication : Application() {
val gameDb: GameDb by lazy { GameDb.getDatabase(this) }
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name=".MyApplication"
...>
<activity
android:name=".MainActivity"
...>
...
</activity>
</application>
</manifest>
class MainActivity : ComponentActivity() {
private lateinit var gameDb: GameDb
private lateinit var playerFlow: MutableStateFlow<List<Player>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
...
}
gameDb = (application as MyApplication).gameDb
playerFlow = MutableStateFlow<List<Player>>(listOf<Player>())
lifecycleScope.launch(Dispatchers.Default) {
val _list = gameDb.playerDao().fetchTopX(10)
playerFlow.value = _list
}
}
...
}
Applicationを介して参照するRoomDatabase(GameDb)インスタンスは、どのコンポーネント(Activity)からも共有さます。
関連記事:
