在多个片段中使用 Room 数据库

Using Room database in multiple fragments

我有 HomeActivity activity,其中有底部导航栏和 5 个片段。我想在所有这些片段中使用 RoomDatabase。我该如何实施?

首页活动代码:

public class HomeActivity extends AppCompatActivity {

    TextView tvDailyGoalValue;
    SharedPreferences sharedPreferences;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //layout setting
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_profile, R.id.navigation_notifications)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.fragment3);
        NavigationUI.setupWithNavController(navView, navController);
       sharedPreferences = getSharedPreferences("MyPrefs", MODE_PRIVATE);
       RoomDB roomDB = Room.databaseBuilder(this, RoomDB.class,"dripDB").build();        
    }    
}

您应该创建一个全局可访问的 RoomDB 对象实例。 Room 文档甚至这样说:

If your app runs in a single process, you should follow the singleton design pattern when instantiating an AppDatabase object. Each RoomDatabase instance is fairly expensive, and you rarely need access to multiple instances within a single process.

您可以通过多种方式在多个 Activity 和 Fragment 之间共享单个对象,例如:

  1. 使用 Dagger 并配置一个 @Singleton,您可以在所有相关活动和片段中 @Inject。如果您是第一次设置 Dagger,设置起来会有些复杂,但这是专业应用程序中的通常选择。
  2. 使用经典的 Java 单例设计模式并将 RoomDB 转换为单例。
  3. 使用自定义 Application 子类,将 RoomDB 实例放在那里并将其公开给任何 Context,例如((YourCustomApplication)context.getApplication()).getRoomDB()

我认为您最好的选择是 1) 可扩展性或 2) 简单性。

我并不是说使用 Android Room is or should be complicated but, definitely not as simple as you think it is; looking to your example. Android developers spend a lot of time trying to learn how to use Android Architecture Components and Dagger 2 可以使他们的应用程序尽可能好,顺便说一下,Google 推荐的 API 可以与 [=51] 一起使用=] 房间。不过,我还是要回答你的问题。

1.实体
决定您要在数据库中使用的实体。假设我们这里只有一个实体。类似于:

@Entity
class User constructor(
    @ColumnInfo(name = "first_name")
    var firstName: String,

    @ColumnInfo(name = "last_name")
    var lastName: String

    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
)

2。 DAO class
像这样创建你的 DAO class:

/**
 * Provides the abstraction API for accessing data.
 */
@Dao
interface AppDao {

    /**
     * Inserts a new [User].
     * @param user The user to insert.
     */
    @Insert
    suspend fun insertUser(user: User)

    /**
     * Updates the specified [User].
     * @param user The user to update.
     */
    @Update
    suspend fun updateUser(user: User)

    /**
     * Deletes the specified [User] from the database.
     * @param user The user to delete.
     */
    @Delete
    suspend fun deleteUser(user: User)
}

3。数据库 class
在单独的 class 中创建您的数据库。 (例如 AppDatabase.java) 这是一个好的数据库 class 的样子:

@Database(entities = [User::class], version = AppDatabase.VERSION)
abstract class AppDatabase : RoomDatabase() {

    /**
     * Returns the DAO for this application.
     * @return The DAO for this application.
     */
    abstract fun getAppDao(): AppDao

    companion object {

        private const val TAG = "AppDatabase"

        const val VERSION = 1
        private const val DATABASE_NAME = "inventory_database.db"

        @Volatile
        private var instance: AppDatabase? = null

        /**
         * Gets and returns the database instance if exists; otherwise, builds a new database.
         * @param context The context to access the application context.
         * @return The database instance.
         */
        fun getInstance(context: Context): AppDatabase =
            instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }

        /**
         * Creates and returns the callback object to execute when the database is first created.
         * @return The callback object to execute when the database is first created.
         */
        private fun appDatabaseCallback(): Callback = object : Callback() {

            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                Log.d(TAG, "Database has been created.")

                // Throws exception
                CoroutineScope(Dispatchers.IO).launch {
                    instance?.getAppDao()?.let { populateDbAsync(it) }
                }
            }

            override fun onOpen(db: SupportSQLiteDatabase) {
                super.onOpen(db)
                Log.d(TAG, "Database has been opened.")
            }
        }

        /**
         * Builds and returns the database.
         * @param appContext The application context to reference.
         * @return The built database.
         */
        private fun buildDatabase(appContext: Context): AppDatabase {
            val filesDir = appContext.getExternalFilesDir(null)
            val dataDir = File(filesDir, "data")
            if (!dataDir.exists())
                dataDir.mkdir()

            val builder =
                Room.databaseBuilder(
                    appContext,
                    AppDatabase::class.java,
                    File(dataDir, DATABASE_NAME).toString()
                ).fallbackToDestructiveMigration()

            // Execute the callback only in DEBUG mode.
            if (BuildConfig.DEBUG) {
                builder.addCallback(appDatabaseCallback())
            }
            return builder.build()
        }

        /**
         * Populates the database when it is first created, as a suspended operation.
         * @param appDao The application DAO to execute queries.
         */
        private suspend fun populateDbAsync(appDao: AppDao) {

            withContext(Dispatchers.IO) {
                // Populate your database here...
            }

        }
    }
}

4.活动与片段

  • Activity
class MainActivity : AppCompatActivity() {

    private lateinit var dao: AppDao

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Initialize the DAO..
        dao = AppDatabase.getInstance(requireContext()).getAppDao()
    }

    // An example of how to execute a dao method in an activity (Again, not recommended)
    private fun insertUser(firstName: String, lastName: String) {
        val user = User(firstName, lastName)
        
        lifecycleScope.launch { 
            dao.insertUser(user)
        }
    }

    // The rest of the code here...
}

您可以对所有活动执行相同的操作。

  • 片段
class ExampleFragment : Fragment(R.layout.fragment_example) {

    private lateinit var dao: AppDao

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Initialize the DAO..
        dao = AppDatabase.getInstance(requireContext()).getAppDao()
    }

    // An example of how to execute a dao method in a fragment (Again, not recommended)
    private fun insertUser(firstName: String, lastName: String) {
        val user = User(firstName, lastName)
        
        lifecycleScope.launch { 
            dao.insertUser(user)
        }
    }

    // The rest of the code here...
}

您可以对所有片段执行相同的操作。