I am trying to make a simple Kotlin Class user for Android and i would like to save the username to keep it when closing and reopening the application
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
class User (var username : String){
private val PREFERENCE_FILE_KEY = "AppPreference"
private val KEY_USERNAME= "prefUserNameKey"
private val sharedPref : SharedPreferences = activity?.getSharedPreferences(PREFERENCE_FILE_KEY, MODE_PRIVATE)
fun Save(){
with (sharedPref.edit()) {
putString(KEY_USERNAME, username)
commit()
}
}
fun Load(){
teamname = sharedPref.getString(KEY_SAVENAME, "Default")?:"Default"
}
}
I have a first question :
android studio says sharedPref.getString(KEY_SAVENAME, "Default") is a String?, but then what is the purpose of the default value here then ?
And secondly, my real problem here is that the activity? keyword has an unresolved reference.
Better practice is to pass shared preference instance when constructing user object because user class shouldn't care how shared preferences is built or about activity:
class User (var username : String, private val sharedPref : SharedPreferences){
}
Also, when getting shared preference instance, use application context not activity to prevent memory leaks:
val sharedPref : SharedPreferences = applicationContext.getSharedPreferences(PREFERENCE_FILE_KEY, MODE_PRIVATE)
val user = User("username", sharedPref)
user.Save()
Firstly, sharedPref.getString(KEY_SAVENAME, "Default") returns a String?, because the "Default"- String can be null. For more information look here.
Secondly, try using
preferences = PreferenceManager.getDefaultSharedPreferences(context)
to initiate the preference instance.
private lateinit var sharedpreferences: SharedPreferences
companion object {
val mypreference = "mypref"
val Name = "nameKey"
}
private fun Save(userName : String) {
val editor = sharedpreferences.edit()
editor.putString(Name, userName)
etName.setText("username")
editor.apply()
}
private fun Get(userName: String) {
sharedpreferences = getSharedPreferences(mypreference, Context.MODE_PRIVATE)
if (sharedpreferences.contains(Name)) {
val setString = sharedpreferences.getString(Name, userName)
etName.setText(getString)
}
}
//Call funtion in onCreate method
private fun containUserString(){
sharedpreferences = getSharedPreferences(mypreference, Context.MODE_PRIVATE)
if (sharedpreferences.contains(Name)) {
val setString = sharedpreferences.getString(Name, "")
etName.setText(getString)
}
}
Related
There are two classes MainActivity and PickTimeForNotif in my project. In MainActivity getSharedPreferences works just fine, i can save my data and get it back. In PickTimeForNotif, however, the same method seems to do nothing.
Here's my simplified MainActivity class:
class MainActivity : AppCompatActivity(), ChangeCupDialogFragment.StringListener {
#SuppressLint("SetTextI18n")
//this is variable i'm saving
private var drankToday = 0
//function in which i save my value to SharedPreferences
private fun saveWaterCountToInternalStorage(clickCounter: Int) {
val sharedPref = this.getSharedPreferences("something", Context.MODE_PRIVATE)
with (sharedPref.edit()){
putInt(getString(R.string.clickCount), clickCounter)
apply()
}
}
//and here i get it from there
private fun loadWaterCountToInternalStorage(): Int {
val sharedPref = this.getSharedPreferences("something", Context.MODE_PRIVATE)
return sharedPref.getInt(getString(R.string.clickCount), drankToday)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val setupNotifButton = findViewById<Button>(R.id.setupNotifButton)
setupNotifButton.setOnClickListener{
val notifIntent = Intent(applicationContext, PickTimeForNotif::class.java)
startActivity(notifIntent)
}
}
}
In setOnClickListener i intend my second activity PickTimeForNotif, here it is.
class PickTimeForNotif: AppCompatActivity(), TimePickerFragment.OnCompleteListener {
val APP_PREFERENCES = "settings"
private val SAVED_FROM_HOUR = "SetFromHour"
private var FROM_HOUR = 99
private fun saveTimeToInternalStorage(prefName1: String, Hour:Int) {
val sharedPref = this.getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE)
with (sharedPref.edit()){
putInt(prefName1, Hour)
apply()
}
}
private fun loadTimeFromInternalStorage() {
val sharedPref = this.getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE)
if (sharedPref.contains(APP_PREFERENCES)) {
sharedPref.getInt(SAVED_FROM_HOUR, FROM_HOUR)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.pick_time_activity)
saveTimeToInternalStorage(SAVED_FROM_HOUR, 1)
loadTimeFromInternalStorage()
Toast.makeText(applicationContext,"$FROM_HOUR", Toast.LENGTH_SHORT).show()
}
}
In the code above i'm trying to set value (1 for example ) to a SAVED_FROM_HOUR key and then get it back and assign to FROM_HOUR variable. However, the Toast shows 99, which means that new data wasn't loaded properly. I tried putting all code from loadTimeFromInternalStorage and saveTimeToInternalStorage to onCreate, but the result is same.
I also tried checking if the Preferences file exists after i call getSharedPreferences with
if (sharedPref.contains(APP_PREFERENCES))
but it does not.
So i'm asking to explain what am i doing wrong and why i can save the data in my MainActivity, but not in the second one. Thanks alot to anyone in advance!!
In loadTimeFromInternalStorage(), you are fetching the value but not assigning to variable like this:
private fun loadTimeFromInternalStorage() {
val sharedPref = this.getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE)
if (sharedPref.contains(APP_PREFERENCES)) {
FROM_HOUR = sharedPref.getInt(SAVED_FROM_HOUR, FROM_HOUR)
}
}
Also, in this line FROM_HOUR = sharedPref.getInt(SAVED_FROM_HOUR, FROM_HOUR), the last parameter in getInt() method is the default value so you should make another constant for it or supply it 0.
I'm using SharedPreferences in SettingsFragment:
val myPrefs = activity?.getSharedPreferences("myPrefs", Context.MODE_PRIVATE) ?: return
val testEnvEnabled = myPrefs.getBoolean(getString(R.string.saved_test_env_key), false)
This is working just fine.
Then I need to ready those preferences in object Api : KoinComponent {
I cannot get there context or activity.
Is there some another way to get information from shared preferences?
For me it's important just to save one information, if test env. is on or off.
I'm saving that information in SettingsFragment over switch.
Thank you
You can use Like this;
class Api : KoinComponent {
private val sharedPreferences by inject<SharedPreferences> {
parametersOf("myPref")
}
fun test() {
sharedPreferences.edit().putInt("Test", 1).commit()
}
fun get(): Int {
return sharedPreferences.getInt("Test", -1)
}
}
val sharedPreferences = module {
factory { key ->
androidContext().getSharedPreferences(key.get<String>(0), Context.MODE_PRIVATE)
}
factory {
Api()
}
}
class App : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this#App)
modules(sharedPreferences)
}
}
}
enter code here
I am writing Junit test for shared preferences but facing below issue
Method
public void storeUser(User user) {
final SharedPreferences userPrefs = context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE);
userPrefs.edit().putString(USER_ID_KEY, user.getUserID()).apply();
}
Junit Class
class UserRepoTest {
private lateinit var context: Context
private lateinit var userRepo: UserRepo
private lateinit var userPrefs: SharedPreferences
private lateinit var editor: SharedPreferences.Editor
#Before
fun setup() {
context = mock()
userRepo = UserRepo(context)
userPrefs = mock()
editor = mock()
}
#Test
fun `check mocked instances are not null`() {
context assertNotEquals null
userRepo assertNotEquals null
}
#Test
fun `when store user then load user`() {
whenever(context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE)).thenReturn(userPrefs)
whenever(userPrefs.edit()).thenReturn(editor)
val user = getUser()
verify(editor, times(1)).putString(USER_ID_KEY, user!!.userID).apply()
// verify(userPrefs.edit(), times(1)).putString(USER_ID_KEY, user!!.userID).apply()
userRepo.storeUser(user)
}
private fun getUser(): User? {
return User().apply {
userID = "test#yopmail.com"
}
}
companion object {
const val USER_PREFS = "userprefs"
const val USER_ID_KEY = "UserID";
}
}
but getting below error not sure why its saying not invoked
Wanted but not invoked:
editor.putString(
"UserID",
"test#yopmail.com"
);
-> at com.example.UserRepoTest.when store user then load user(UserRepoTest.kt:41)
Actually, there were zero interactions with this mock.
Order is important. Call the action storeUser() before you try to verify what it did.
This is the function I made in one fragment to store my value,
private fun nickdata(){
val sharedPreferences = getSharedPreferences("sharedPrefs", Context.MODE_PRIVATE)
val nicdat = binding.nickname.text.toString()
val editor = sharedPreferences.edit()
editor.putString("Nickname_key","trial")
editor.apply()
editor.commit()}
below is the code I am using to fetch data in another fragment
val pref = activity!!.getPreferences(Context.MODE_PRIVATE)
val id = pref.getString("Nickname_Key", "trial")
binding.nickdata.text = id
In output I am getting "trial" which is def value.
Make sure you are using the same shared preference in both fragments.
Also what you did is you stored the value trial not the value that you want to send the the other fragment.
val sharedPreferences = activity!!.getSharedPreferences("sharedPrefs", Context.MODE_PRIVATE)
val nicdat = binding.nickname.text.toString()
val editor = sharedPreferences.edit()
editor.putString("Nickname_key",nicdat)
editor.apply()
editor.commit()
For the other fragment
val pref = activity!!.getSharedPreferences("sharedPrefs", Context.MODE_PRIVATE)
val id = pref.getString("Nickname_Key", "trial")
binding.nickdata.text = id
You can use Fragment Result Listeners. More documentation: Communicating between fragments. Here is some working code that controls navigation in my app:
In first fragment:
open fun navigate(idOfDestination: Int, bundle: Bundle?) {
val tempBundle = bundle ?: Bundle()
tempBundle.putInt(NAVIGATION_DESTINATION, idOfDestination)
activity?.supportFragmentManager?.setFragmentResult(NAVIGATION_RESULT, tempBundle)
}
In target fragment, register the listener:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.supportFragmentManager?.setFragmentResultListener(NAVIGATION_RESULT, this, FragmentResultListener { _, bundle ->
val destination = bundle.getInt(NAVIGATION_DESTINATION)
bundle.remove(NAVIGATION_DESTINATION)
navigationHandler(bundle,destination)
})
}
private fun navigationHandler(bundle: Bundle?, idOfDestination: Int) {
navController = Navigation.findNavController(binding.root)
if (!FeatureControlManager.isDestinationAllowedToGo(idOfDestination)) {
navController = childFragmentManager.fragments.first().findNavController()
}
navController.validateAndNavigate(navController, idOfDestination, childFragmentManager, bundle)
}
I got it done
private fun nickdata(){
val sharedPreferences = getSharedPreferences("sharedPrefs", Context.MODE_PRIVATE)
val nicdat = binding.nickname.text.toString()
val editor = sharedPreferences.edit()
editor.putString("trial",nicdat)
editor.apply()
editor.commit()
this code in one fragment
below mentioned code where I want to fetch it
val pref = activity!!.getSharedPreferences("sharedPrefs", Context.MODE_PRIVATE)
val nicdat = binding.nickdata.text.toString()
val id = pref.getString("trial", nicdat)
binding.nickdata.text = id
I tried to follow this tutorial, but an error occured when I try to assign a value to my Sh.Preference (prefs.token = "sometoken"):
kotlin.UninitializedPropertyAccessException: lateinit property prefs has not been initialized
I don't understand where's the bug, I also checked this thread.
Here are my code snippets
Prefs.kt :
class Prefs(context: Context) {
private val PREFS_FILENAME = "com.example.myapp.prefs"
private val PREFS_TOKEN = "token"
private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_FILENAME, 0)
var token: String?
get() = prefs.getString(PREFS_TOKEN, "")
set(value) = prefs.edit().putString(PREFS_TOKEN, value).apply()
}
App.kt :
val prefs: Prefs by lazy {
App.prefs
}
class App : Application() {
companion object {
lateinit var prefs: Prefs
}
override fun onCreate() {
prefs = Prefs(applicationContext)
super.onCreate()
}
}
prefs.token has a default value of "", so why the logs said that has not been initialized?
Ok, problem found... The code was alright, I just missed to add this line
android:name=".App"
in the tag
<application in my Android Manifest.
In my case, i just initialize SharedPreference in onCreate(), and all works
For example: MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppPreferences.init(this) // added this
}
SharedPreferences object:
object AppPreferences {
private const val NAME = "SpinKotlin"
private const val MODE = Context.MODE_PRIVATE
private lateinit var preferences: SharedPreferences
// list of app specific preferences
private val IS_FIRST_RUN_PREF = Pair("is_first_run", false)
fun init(context: Context) {
preferences = context.getSharedPreferences(NAME, MODE)
}
/**
* SharedPreferences extension function, so we won't need to call edit() and apply()
* ourselves on every SharedPreferences operation.
*/
private inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) {
val editor = edit()
operation(editor)
editor.apply()
}
// getter and setter with Shared Preference
var temperature: Float
// custom getter to get a preference of a desired type, with a predefined default value
get() = preferences.getFloat("temp",1f )
// custom setter to save a preference back to preferences file
set(value) = preferences.edit {
it.putFloat("temp", value)
}
}