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)からも共有さます。
関連記事: