I am currently creating an Android application using Android Studio and I have a question or two regarding what the most appropriate way of initializing "stuff" is.
As of right now I do the initializing in the onCreate
method of the MainActivity
which also serves as the "main"/"launcher" activity.
The initializing consists of
- creating a room-database that will be used later on
- Regarding the creating/fetching of the database, seemingly the written code below works to get the instance object even after the database has already been created once. This leaves me to think that perhaps I shouldn't be building another one with the same name but instead fetch it from somewhere? At the same time seemingly the
databaseBuilder()
seems to be returning the existing instance if it exists... so the code works anyway but is it appropriate?
- Regarding the creating/fetching of the database, seemingly the written code below works to get the instance object even after the database has already been created once. This leaves me to think that perhaps I shouldn't be building another one with the same name but instead fetch it from somewhere? At the same time seemingly the
- setting the theme mode to light or dark depending on the user's phone mode
- initializing resources from an Android Studio library/API that I am using.
I have a feeling initializing things in this way and in this place (onCreate in MainActivity) is inappropriate and it can (should?) be done elsewhere and in some other way. So my question is How/where should I be doing the initializing of stuff like this?
MainActivity.kt
// ...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//applicationContext.deleteDatabase("database-name")
// Create the database
val achievementDao = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java,"database-name"
).build().achievementDao()
// Just some random "test" code
GlobalScope.launch {
achievementDao.insertAll(Achievement("title1", "desc1", "date1", "false"))
achievementDao.insertAll(Achievement("title2", "desc2", "date2", "true"))
Log.i("database", achievementDao.getAll().toString())
Log.i("database", achievementDao.getAllComplete().toString())
Log.i("database", achievementDao.getAllIncomplete().toString())
}
// Set relevant theme depending on phone's mode (LIGHT or DARK)
val currentNightMode = (resources.configuration.uiMode
and Configuration.UI_MODE_NIGHT_MASK)
when (currentNightMode) {
Configuration.UI_MODE_NIGHT_NO -> {
// Night mode is not active
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
Configuration.UI_MODE_NIGHT_YES -> {
// Night mode is active
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
Configuration.UI_MODE_NIGHT_UNDEFINED -> { }
}
// Load in resources
World.init(applicationContext)
// ...
}
// ...
CodePudding user response:
I'd prefer you to do this task in the custom Application
class. This is how you can create it:
- Create a new class named
MyApplication.kt
or anything you want. - Make it to extend
Application
- There, in the
onCreate()
method, you can do all the tasks for your initialisation. - You must pass that class in the manifest like this:
<application> android:name=".MyApplication" ... </application>
To know more about Application class, refer to this site.
CodePudding user response:
Regarding the creating/fetching of the database, seemingly the written code below works to get the instance object even after the database has already been created once. This leaves me to think that perhaps I shouldn't be building another one with the same name but instead fetch it from somewhere? At the same time seemingly the databaseBuilder() seems to be returning the existing instance if it exists... so the code works anyway but is it appropriate?
When you build the database, it doesn't in fact create the database. It builds an instance that will open or create the database when it is accessed (typically via a Dao, but can be done otherwise).
So in your case the database is only created when achievementDao.insertAll(Achievement("title1", "desc1", "date1", "false"))
runs.
Without going in too deep. The @Database
annotated class instance will see if the database (the file named database-name) exists (at location data/data/databases/database-name). If the file does not exist then the database (and therefore the file) will be created. If it exists, then it will be accessed/opened via the underlying SQLite API.
As such it doesn't really matter where you access the database, application or the first activity (reading further and implemnting the onCreate Callback, it simple does not matter where at all).
However, you do need to be careful in that you don't inadvertently keep adding the data whenever the App is run, or that you handle conflicts (e.g. a unique constraint can be ignored via the onConflict =
parameter of an @Insert
).
What you may well wish to consider, is using the onCreate
callback. This will only run once for the lifetime of the database (as it says when the database is first created), thus the data added is added once and only the once (no resource wasteful attempts to add data only for it to be ignored etc), the drawback is that you can't use the Dao's (they will not have been fully instantiated at this stage). Rather you need to use the SupportSQLiteDatabase passed to the onCreate
method of the callback, and the methods available to it such as execSQL, insert etc.
see https://developer.android.com/reference/androidx/room/RoomDatabase.Callback
Another option is to utilise a pre-packaged database, where the database, with some data is placed into the assets folder (doesn't have to have data but without it's a bit of a waste). Here you would use the .createFromAsset
method/function added to the invocation of the databaseBuilder
. This is preferable if there is a large amount of data, rather than bulking up the code