I am trying to implement an option item in my action bar, where the user can select whether they want the app to be light or dark theme, then store that persistently using SharedPreferences and get the same theme they picked once app relaunches.
I first instantiated my SharedPrefs in my Application.kt class: `
class App : Application() {
init {
instance = this
}
companion object {
private var instance: Application? = null
lateinit var room: Postdb
lateinit var retrofit: Retrofit
lateinit var sharedPreferences: SharedPreferences
fun applicationContext() : Context {
return instance!!.applicationContext
}
}
override fun onCreate() {
room = Room.databaseBuilder(
applicationContext,
Postdb::class.java,
Postdb.DATABASE_NAME
).build()
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
sharedPreferences = getSharedPreferences("MySharedPref", MODE_PRIVATE)
super.onCreate()
}
}
Then, in MainActivity.kt , I implemented this:
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.mymenu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
var editor = App.sharedPreferences.edit()
when(item.itemId){
R.id.menuRead ->
{
Toast.makeText(this,"Pulling data from Room",Toast.LENGTH_SHORT).show()
}
R.id.menuDelete ->
{
Toast.makeText(this,"Deleting data from Room",Toast.LENGTH_SHORT).show()
viewModel.deleteData()
}
R.id.lightTheme ->
{
Toast.makeText(this,"Switching to Light Theme!",Toast.LENGTH_SHORT).show()
AppCompatDelegate.setDefaultNightMode(light)
editor.putInt("light", light)
editor.apply()
}
R.id.darkTheme ->
{
Toast.makeText(this,"Switching to Dark Theme!",Toast.LENGTH_SHORT).show()
AppCompatDelegate.setDefaultNightMode(dark)
editor.putInt("dark", dark)
editor.apply()
}
}
// editor.commit()
return true
}
`
Finally, under onCreate() I implemented this: `
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel : MainViewModel by viewModels()
var light = AppCompatDelegate.MODE_NIGHT_NO
var dark = AppCompatDelegate.MODE_NIGHT_YES
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val sp : SharedPreferences = App.applicationContext().getSharedPreferences("MySharedPref", MODE_PRIVATE)
//val theme = sp.getInt("light",dark)
val theme = sp.getInt("dark",light)
if(theme == 1){
AppCompatDelegate.setDefaultNightMode(theme)}
else{
AppCompatDelegate.setDefaultNightMode(light)
}
`
The whole idea is that when the user selects "Dark Theme" option, it is saved via Shared Prefs, and then if app re-launches, it is still in "Dark Theme" as the default option should be just light theme.
Before implementing sharedprefs, I can switch between themes correctly but obviously they did not save. However, after implementing sharedprefs, the I cannot switch themes.
Any help or guidance would be much appreciated!
CodePudding user response:
You're using two different preference keys, "light" and "dark", for the same setting, which doesn't really make sense. Your onCreate()
only looks at whatever was put in the "dark" key, but when the user chooses a light theme, you never write to that "dark" key, only the "light" key. This means your code will never detect that the light theme was chosen.
Instead, create a single key. I think it makes sense to call it night mode, since you are storing an int that represents which mode to use. You should always put keys into a constant so you don't have to worry about typos.
// At top level or in some object:
const val KEY_NIGHT_MODE = "nightMode"
// Menu options:
R.id.lightTheme ->
{
Toast.makeText(this,"Switching to Light Theme!",Toast.LENGTH_SHORT).show()
AppCompatDelegate.setDefaultNightMode(light)
editor.putInt(KEY_NIGHT_MODE, light)
editor.apply()
}
R.id.darkTheme ->
{
Toast.makeText(this,"Switching to Dark Theme!",Toast.LENGTH_SHORT).show()
AppCompatDelegate.setDefaultNightMode(dark)
editor.putInt(KEY_NIGHT_MODE, dark)
editor.apply()
}
// Reading and applying the value in onCreate (no if/else needed):
val theme = sp.getInt(KEY_NIGHT_MODE, light)
AppCompatDelegate.setDefaultNightMode(theme)
I should also point out a couple of code smells I see:
These light and dark properties are redundant. You should use the constants directly where they are needed. Also, the fact that these are mutable properties is very weird. You would never have a reason to change them, so it is just inviting possible bugs that you don't need to.
var light = AppCompatDelegate.MODE_NIGHT_NO
var dark = AppCompatDelegate.MODE_NIGHT_YES
In this code you explicitly get a SharedPreferences that is the same as the one already defined in your Application's companion object. That's redundant and error prone.
val sp : SharedPreferences = App.applicationContext().getSharedPreferences("MySharedPref", MODE_PRIVATE)
I'd replace it with, since that's what you're already using in your onOptionsItemSelected()
:
val sp = App.sharedPreferences