sorry for newbie question but I'm starting with Kotlin and Android app development. Currently I'm trying to create simple Activity that will switch background colors. I add 2 buttons that are working and switching colors between white and green, but would you be able to help me how to save it between the session using sharedPreferences ? I cannot retrieve these states from the preferences. Code sample below:
class OptionsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_options)
val prefs = getSharedPreferences("bgColour", Context.MODE_PRIVATE)
val editor = prefs.edit()
bt3.setOnClickListener {
Screen.setBackgroundColor(Color.GREEN)
}
bt4.setOnClickListener {
Screen.setBackgroundColor(Color.WHITE)
}
}
}
You need to save the color in your preferences:
val prefs = getSharedPreferences("bgColour", Context.MODE_PRIVATE)
//Retrieve the saved value, default is false.
if (prefs.getBoolean("isGreen", false)) {
Screen.setBackgroundColor(Color.GREEN)
} else {
Screen.setBackgroundColor(Color.WHITE)
}
val editor = prefs.edit()
//Save on button click
bt3.setOnClickListener {
Screen.setBackgroundColor(Color.GREEN)
editor.putBoolean("isGreen", true)
editor.apply()
}
bt4.setOnClickListener {
Screen.setBackgroundColor(Color.WHITE)
editor.putBoolean("isGreen", false)
editor.apply()
}
You can read more about saving key-value pairs here.
Related
In my SettingActivity I'm loading some data to be shown in ListPreference from Room, once the items are selected all works correctly, the value is saved to `SharedPreferences and the summary is shown correctly, but once I return to SettingsActivity the summary value is reset to null.
Here is what is happening:
My code is pretty simple, onViewCreated() I start observing LiveData to be shown in ListPreference and then I set the values for entries and entryValues
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.shops.observe(viewLifecycleOwner) {
setShopsPreferences(it)
}
}
private fun setShopsPreferences(shops: List<Shop>) {
val shopsPreference = preferenceManager.findPreference<ListPreference>("defaultShop")
if (shops.isEmpty()) {
shopsPreference?.isEnabled = false
return
} else {
shopsPreference?.isEnabled = true
}
val entries: ArrayList<String> = ArrayList()
val entryValues: ArrayList<String> = ArrayList()
shops.forEach {
entries.add(it.description)
entryValues.add(it.id)
}
shopsPreference?.entryValues = entryValues.toArray(arrayOfNulls<CharSequence>(entryValues.size))
shopsPreference?.entries = entries.toArray(arrayOfNulls<CharSequence>(entries.size))
}
ViewModel:
#HiltViewModel
class ShopsViewModel #Inject constructor(repository: ShopsRepository) : ViewModel() {
private val _shops = MutableLiveData<List<Shop>>()
val shops: LiveData<List<Shop>> = _shops
init {
repository.getAllShops().observeForever {
_shops.value = it
}
}
}
Repository:
fun getAllShops(): LiveData<List<Shop>> {
return shops.select()
}
DAO:
#Dao
interface ShopsDAO {
#Query("SELECT * FROM shops")
fun select(): LiveData<List<Shop>>
}
You are populating list entries dynamically after the preference hierarchy is already created by inflating the xml. But during that time there was no entry, hence the value was null. The data was then retrieved asynchronously but the change will not be reflected. So you have to set the summary manually.
Another approach I'm not sure about is to call recreate on the activity after populating the data inside the observer listener.
To resolve the issue with dynamic data in a ListPreference I've made some changes to my code, first of call in onCreatePreferences() I've added a preference listener to my ListPreference like this:
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
val shopsPreference = preferenceManager.findPreference<ListPreference>("defaultShop")
shopsPreference?.setOnPreferenceChangeListener { preference, newValue ->
val description = viewModel.shops.value?.find { it.id == newValue }
preference.summary = description?.description
true
}
}
So in that way on each new selection, I'm looking for the matching value for that preference in my ViewModel and getting the description for it which then is set as the summary.
While to set the summary every time the list has been changed or the SettingsActivity is opened I've added the following code to my setShopsPreferences() function:
private fun setShopsPreferences(shops: List<Shop>?) {
if (shops == null) {
return
}
val shopsPreference = preferenceManager.findPreference<ListPreference>("defaultShop")
// The preference is enabled only if there are shows inside the list
shopsPreference?.isEnabled = shops.isNotEmpty()
// Getting the defaultShop preference value, which will be used to find the actual shop description
val defaultShop = sharedPreferences.getString("defaultShop", "0")
defaultShop?.let { shopId ->
// Setting the summary based on defaultShop saved preference
shopsPreference?.summary = shops.find { it.id == shopId }?.description
}
val entries: ArrayList<String> = ArrayList()
val entryValues: ArrayList<String> = ArrayList()
shops.forEach {
entries.add(it.description)
entryValues.add(it.id)
}
shopsPreference?.entryValues =
entryValues.toArray(arrayOfNulls<CharSequence>(entryValues.size))
shopsPreference?.entries = entries.toArray(arrayOfNulls<CharSequence>(entries.size))
}
Whenever I open the app and click the switch, dark mode turns on and it stays in the position. However, if I relaunch the app, the switch goes back to default, and dark mode is still on. How would I do this in Kotlin?
Also, is there any reference code for this in Kotlin?
Create Pref class for storing data.
class Prefs (private val context: Context)
private fun getSharedPreferences(prefsName: String) =
context.getSharedPreferences(prefsName, Context.MODE_PRIVATE)
private val PREF_KEY = "pref_key"
private val KEY_VALUE = "key_value"
private val prefValue by lazy { getSharedPreferences(PREF_KEY) }
var currentModeDayNight: Boolean
get() {
return prefValue.getBoolean(KEY_VALUE, false)
}
set(value) {
prefValue.edit().putBoolean(KEY_VALUE, value).apply()
}
Then store data for default dayNightMode.
You may just need to restart your app. But keep in mind, that this code enables the Dark Mode System-wide, not just in App:
public static void setNightMode(Context target){
UiModeManager uiManager = (UiModeManager) target.getSystemService(Context.UI_MODE_SERVICE);
if (VERSION.SDK_INT <= 22) {
uiManager.enableCarMode(0);
}
val pref = Pref(context)
if (pref.currentModeDayNight) {
pref.currentModeDayNight = false
uiManager.setNightMode(UiModeManager.MODE_NIGHT_YES);
} else {
pref.currentModeDayNight = true
uiManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
}
}
I'm working on timer app using kotlin. My requirement is to save multiple time values in preferences. For that purpose I have made a separate class for preferences.
This is the work done by me.
In PrefUtil class
private const val ElAPSED_TIME_VALUE_ID = "com.code.kotlin.elapsed_time"
private var incrementedValue = 0
fun getElapsedTime(context: Context) : Long {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getLong(ElAPSED_TIME_VALUE_ID , 0)
}
fun setElapsedTime(elapsedTime: Long, context: Context) {
val editor = PreferenceManager.getDefaultSharedPreferences(context).edit()
editor.putLong(ElAPSED_TIME_VALUE_ID, elapsedTime)
editor.apply()
}
On toggle button
btnToggle.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
startTimer()
timerState = TimerState.Running
showStartTime()
startingTime = System.currentTimeMillis()
PrefUtils.setStartTimeValue(startingTime, this)
Toast.makeText(applicationContext, "Timer is Running", Toast.LENGTH_SHORT).show()
} else {
timer.cancel()
onTimerFinished()
elapsedTime()
PrefUtils.getElapsedTime(this)
Toast.makeText(applicationContext, "Timer is Stopped", Toast.LENGTH_SHORT).show()
}
For saving elapsed time in preferences and then to get from there
private fun elapsedTime() {
val endingTime = System.currentTimeMillis()
val startTime = PrefUtils.getStartTimeValue(this)
elapsedTime = (-startTime + endingTime)
PrefUtils.setElapsedTime(elapsedTime, this)
}
private fun showElapsedTime() {
val minut = (PrefUtils.getElapsedTime(this) / 1000) / 60
val sec = (PrefUtils.getElapsedTime(this) / 1000) % 60
val elpTime: TextView = findViewById(R.id.elpTime)
elpTime.text = "Elapsed time: $minut : $sec "
}
On pressing pause button I want to show saved multiple time values..
fabPause.setOnClickListener {
timer.cancel()
timerState = TimerState.Paused
updateButtons()
showElapsedTime()
}
Now the problem is that when I close the app after getting one preference value the time value is automatically removed from preferences. On next session it is saved as new.. While I want to save and show multiple time values in multiple sessions. What should I do???
Need Your Help.......!
If you want to save all the timestamps using the same ElAPSED_TIME_VALUE_ID key, you can use e.g. SharedPreferences.Editor.putStringSet(). Or you can concat them to things like "timestamp1:timestamp2" then parse the string manually.
I'm trying to do a function that will only save a higher speed than the one already saved.
But the var outside the if loop is always 0.0, inside value is different. Does anyone knows some resolve or even better idea how to save only maximum speed?
private fun updateUI(speed: Double, distance: Double){
val df = DecimalFormat("0.0")
speed_text_view.text = df.format(speed).plus(" km/h")
distance_text_view.text = df.format(distance)
Log.e("getLocationUpdates", df.format(speed))
var getSpeedDouble = 0.0 //here is problem. The value doesn't change
if (speed > getSpeedDouble) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
val editor = sharedPref.edit()
editor
.putString("SPEED", speed.toString())
.apply()
val getSharedPref = PreferenceManager.getDefaultSharedPreferences(this)
getSharedPref.apply {
val getSpeed = getString("SPEED", "")
getSpeedDouble = getSpeed!!.toDouble()
Log.e("GetSpeedDouble", getSpeedDouble.toString())
max_speed_text_view.text = getSpeed.toString()
}
}
}
For posterity:
Have the speed as a global variable.
val speed:Double = 0.0
when you load the activity fetch its value from the shared preferences:
val preference = getSharedPreferences(yourApp, Context.MODE_PRIVATE)
val editor = preference.edit()
speed = preference.getDouble(“SPEED”,0.0)
when you finish the activity write the value back to the shared preferences:
editor.putDouble(“SPEED”,speed)
editor.commit()
within your method just assign a new value to the variable only if the current reading is bigger than the saved value.
private fun updateUI(newSpeed:Double) {
if (newSpeed > speed)
{
speed = newSpeed
textview.setText((newSpeed).toString())
}
}
How about putting it away in a nice class, and when just initializing that class from you activity:
speedKeeper = MaxSpeedKeeper(this)
then all you have to do is drop in your speeds (ie. speedKeeper.speed = 10.4) and it will stay updated.
Apply() will update to disk async, but the value in initialized sharedPref will stay cached, and is read from companion object's maxSpeed anyway.
This way, you can just drop your speedkeeper in any other processes, classes, fragments etc and it will keep doing what it does, or just initialize it again in a new activity.
class MaxSpeedKeeper(context: Context) {
companion object {
const val SPEED = "SPEED"
const val SHAREDPREFS_NAME = "MY_SHAREDPREFS"
var maxSpeed = 0.0f
}
var speed: Double
get() = maxSpeed.toDouble()
set(speedToCheck) {
if (speedToCheck > maxSpeed) {
maxSpeed=speedToCheck.toFloat()
with(sharedPref.edit()) {
putFloat(SPEED, speedToCheck.toFloat()) // you could change this to a string or bits or something if you want more resolution than a float gives
apply()
}
}
}
private val sharedPref =
context.getSharedPreferences(SHAREDPREFS_NAME, Context.MODE_PRIVATE)
init {
maxSpeed = sharedPref.getFloat(SPEED, 0.0f)
}
}
private fun updateUI(speed: Double) {
var getSpeedDouble = 0.0 //here is problem. The value doesn't change
if (speed > getSpeedDouble) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
val editor = sharedPref.edit()
editor.putString("SPEED", speed.toString()).apply()
val defaultSpeed = sharedPref.getString("SPEED", "")
getSpeedDouble = defaultSpeed.toString().toDouble()
Log.e("updateUI", getSpeedDouble.toString())
}
}
private fun getSpeed() {
var getSpeedDouble: Double
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
val defaultSpeed = sharedPref.getString("SPEED", "")
getSpeedDouble = defaultSpeed.toString().toDouble()
Log.e("getSpeed", getSpeedDouble.toString())
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
updateUI(10.0)
getSpeed()
}
output
updateUI: 10.0
getSpeed: 10.0
I created a RatingBar in my application. It is for rating movies. I want value to be saved. When I login and go to that activity, I want to see that stars that I rated. It is difficult for me to find the answer because it is written in Kotlin and I'm new to it.
I searched for many other questions and answers, but with no result. Can you tell me what I need to change in my code?
class MovieDetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_movie_details)
fiveStars()
val sharedPreference = getPreferences(Context.MODE_PRIVATE)
val rating = sharedPreference.getFloat("numStars", 0f)
ratingBar.rating = rating
}
private fun fiveStars() {
val ratingBar = findViewById<RatingBar>(R.id.ratingBar)
ratingBar.onRatingBarChangeListener = RatingBar.OnRatingBarChangeListener()
{ ratingBar: RatingBar, fl: Float, b: Boolean ->
val sharedPreference = getSharedPreferences("numStars", Context.MODE_PRIVATE)
val editor = sharedPreference.edit()
editor.putFloat("numStars", fl)
editor.apply()
Log.d("rate", ratingBar.rating.toString())
}
}
}
I tried a lot of things, but nothing is working. Hope you could help me. Thanks!
It seems like you're using two different preferences.
Here you are calling getPreferences(Context.MODE_PRIVATE):
val sharedPreference = getPreferences(Context.MODE_PRIVATE)
val rating = sharedPreference.getFloat("numStars", 0f)
ratingBar.rating = rating
and here you are using a specific sharedPreferences:
val sharedPreference = getSharedPreferences("numStars", Context.MODE_PRIVATE)
val editor = sharedPreference.edit()
Either use getPreferences(Context.MODE_PRIVATE) in both cases, or use getSharedPreferences("numStars", Context.MODE_PRIVATE) in both cases