I just can't figure out how to use this a fragment. The official documentation shows this example:
val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE) ?: return
val defaultValue = resources.getInteger(R.integer.saved_high_score_default_key)
val highScore = sharedPref.getInt(getString(R.string.saved_high_score_key), defaultValue)
Replacing "getInt" with "getString" always returns ""
val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
val password = sharedPref?.getString("key", "")
if (key == "") {
// this always calls even when I change the value from the settings menu!
} else {
}
This is the simple class use for store any data type (String, Boolean, Int) in SharedPreference:
class PrefUtil(context: Context) {
private val context: Context
val PREFS_NAME = "my_prefs"
fun setInt(key: String?, value: Int) {
val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0)
val editor: SharedPreferences.Editor = prefs.edit()
editor.putInt(key, value)
editor.apply()
}
fun getInt(key: String?, defValue: Int): Int {
val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0)
return prefs.getInt(key, defValue)
}
fun setString(key: String?, value: String?) {
val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0)
val editor: SharedPreferences.Editor = prefs.edit()
editor.putString(key, value)
editor.apply()
}
fun getString(key: String?): String? {
val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0)
return prefs.getString(key, "null")
}
fun setBool(key: String?, value: Boolean) {
val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0)
val editor: SharedPreferences.Editor = prefs.edit()
editor.putBoolean(key, value)
editor.apply()
}
fun getBool(key: String?): Boolean {
val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0)
return prefs.getBoolean(key, false)
}
fun getBool(key: String?, defaultValue: Boolean): Boolean {
val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0)
return prefs.getBoolean(key, defaultValue)
}
init {
this.context = context
}
}
and for store String use:
PrefUtil(this).setString("Key","value")
for getting String from SharedPreference use:
PrefUtil(this).getString("key")
You need to insert a piece of data for this key first, and then call get method:
val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
with (sharedPref.edit()) {
putString("key", "abc123456")
apply()
}
val password = sharedPref?.getString("key", "")
if (password == "") {
// ....
Log.d(TAG,"password is empty.")
} else {
Log.d(TAG,">>>:$password")
}
You can try like this
//For Add String Value in sharedPreferences
val sharedPreferences = getSharedPreferences("key", MODE_PRIVATE) ?: return
with(sharedPreferences.edit()) {
putString("yourStringKey", "Hello World")
apply()
}
//Here get enter string value from sharedPreferences other activity
val sharedPreferences1 = getSharedPreferences("key", MODE_PRIVATE) ?: return
val string = sharedPreferences1.getString("yourStringKey", "hi") //"hi" is default value
Log.e("sharedPreferences1", "sharedPreferences1 Val is -->> $string")
Turns out I actually needed to use SharedPreferences as I'm using a Settings Activity. Thanks for the answers though as they kind of helped to lead in the direction I needed.
Related
private lateinit var sharedPreferences: SharedPreferences
private lateinit var checkBox: CheckBox
private lateinit var chip: Chip
private lateinit var tvNext2CheckBox: TextView
private lateinit var tvNext2Chip: TextView
private lateinit var KEY: String
private var checkBox_value by Delegates.notNull<Boolean>()
private var chip_value by Delegates.notNull<Boolean>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val checkBox = findViewById<CheckBox>(R.id.checkBox)
val tvNext2checkBox = findViewById<TextView>(R.id.tvNext2CheckBox)
val chip = findViewById<Chip>(R.id.chip)
val tvNext2Chip = findViewById<TextView>(R.id.tvNext2Chip)
val sharedPreferences =
applicationContext.getSharedPreferences("PROJECT_NAME", MODE_PRIVATE)
val editor = sharedPreferences.edit()
checkBox.isChecked =
sharedPreferences.contains("KEY") && sharedPreferences.getBoolean("KEY", false) == true
checkBox.setOnClickListener {
if (checkBox.isChecked) {
editor.putBoolean("KEY", true)
editor.apply()
checkBox_value = sharedPreferences.getBoolean("KEY", true)
tvNext2checkBox.text = checkBox_value.toString()
} else {
editor.putBoolean("KEY", false)
editor.apply()
checkBox_value = sharedPreferences.getBoolean("KEY", false)
tvNext2checkBox.text = checkBox_value.toString()
}
}
// code for Chip Button
chip.isChecked =
sharedPreferences.contains("KEY") && sharedPreferences.getBoolean("KEY", false) == true
chip.setOnClickListener {
if (chip.isChecked) {
editor.putBoolean("KEY", true)
editor.apply()
chip_value = sharedPreferences.getBoolean("KEY", true)
tvNext2Chip.text = chip_value.toString()
} else {
editor.putBoolean("KEY", false)
editor.apply()
chip_value = sharedPreferences.getBoolean("KEY", false)
tvNext2Chip.text = chip_value.toString()
}
}
}
}
I have a ListView with items created by
val values = ArrayList<String>().toMutableList()
val adapter = ArrayAdapter(this, R.layout.listview_text_color, values)
adapter.add(title_editText.text!!.toString() + " - " + content_editText.text!!.toString())
I need to save those ListView items and reload them again when reopen the app using SharedPreferences (not DB)
This is my actual code about SP:
fun saveData(values: Set<String>) {
val sharedPref = this.getPreferences(Context.MODE_PRIVATE) ?: return
with(sharedPref.edit()) {
putStringSet("test", values)
putString("title", title_editText.text!!.toString())
putString("content", content_editText.text!!.toString())
apply()
}
}
fun getData() {
val sharedPref = this.getPreferences(Context.MODE_PRIVATE) ?: return
val titleData = sharedPref.getString("title", "")
val contentData = sharedPref.getString("content", "")
Toast.makeText(this, "$titleData $contentData", Toast.LENGTH_LONG).show()
}
EDIT FOR SOLUTION
After full days of research, I went to solution:
In MainActivity.kt create you ArrayList variable as global:
class MainActivity : AppCompatActivity() {
private var values = ArrayList<String>()
... //the rest of your code
}
Then add those 2 functions:
private fun saveData() {
val sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE)
val editor = sharedPreferences.edit()
val gson = Gson()
val json = gson.toJson(values)
editor.putString("task list", json)
editor.apply()
}
private fun loadData() {
val sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE)
val gson = Gson()
val json = sharedPreferences.getString("task list", "")
val type = object: TypeToken<ArrayList<String>>() {
}.type
if(json == null)
values = ArrayList()
else
values = gson.fromJson(json, type)
}
where values is your ArrayList
To save data:
done_fab.setOnClickListener {
values.add("put your string here")
adapter.notifyDataSetChanged() //your array adapter
saveData()
}
And to load data, simply call the function in your MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadData()
val adapter = ArrayAdapter(this, R.layout.listview_text_color, values) //your custom arrayAdapter for the listView
... //the rest of your code
}
Thank you Arfrmann for posting a working resolution that I could use. I had to modify the code to fit inside a Fragment as well as my values being a MutableList of integers. So, I thought I'd share my scenario so that others could benefit.
class NeedsmetFragment : Fragment() {
private var incorrectList = mutableListOf<Int>()
val PREFS_FILENAME = "com.app.app.prefs"
private fun saveData() {
val sharedPreferences = context!!.getSharedPreferences(PREFS_FILENAME, 0)
val editor = sharedPreferences.edit()
val gson = Gson()
val json = gson.toJson(incorrectList)
editor.putString("incorrectList", json)
editor.apply()
}
private fun loadData() {
val sharedPreferences = context!!.getSharedPreferences(PREFS_FILENAME, 0)
val gson = Gson()
val json = sharedPreferences.getString("incorrectList", "")
val type = object: TypeToken<MutableList<Int>>() {}.type
if(json == null || json == "")
incorrectList = mutableListOf<Int>()
else
incorrectList = gson.fromJson(json, type)
}
//...
x++
incorrestList.add(x)
saveData()
loadData()
thisval = incorrectList[x]
}
The proper way to save ArrayList of String to preferences is:
.putStringArrayList("test", values)
and get it
.getStringArrayList("test")
SOLUTION
After full days of research, I went to solution:
In MainActivity.kt create you ArrayList variable as global:
class MainActivity : AppCompatActivity() {
private var values = ArrayList<String>()
... //the rest of your code
}
Then add those 2 functions:
private fun saveData() {
val sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE)
val editor = sharedPreferences.edit()
val gson = Gson()
val json = gson.toJson(values)
editor.putString("task list", json)
editor.apply()
}
private fun loadData() {
val sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE)
val gson = Gson()
val json = sharedPreferences.getString("task list", "")
val type = object: TypeToken<ArrayList<String>>() {
}.type
if(json == null)
values = ArrayList()
else
values = gson.fromJson(json, type)
}
where values is your ArrayList
To save data:
done_fab.setOnClickListener {
values.add("put your string here")
adapter.notifyDataSetChanged() //your array adapter
saveData()
}
And to load data, simply call the function in your MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadData()
val adapter = ArrayAdapter(this, R.layout.listview_text_color, values) //your custom arrayAdapter for the listView
... //the rest of your code
}
All this because SharedPreferences doesn't supports ArrayList<String> storing, so passing them with a JSON is the best option
This is my User class
open class User(val context: Context) : Serializable {
#SerializedName("token")
var tokenFromServer: String = ""
var tokenSharedPreferences: SharedPreferences =context.getSharedPreferences(Constants.USER_TOKEN_PREF, Context.MODE_PRIVATE)
#SerializedName("registered_token")
var token: String = ""
set(userNewToken) {
field = userNewToken
with(tokenSharedPreferences.edit()) {
putString(Constants.TOKEN_KEY, userNewToken).commit()
}
checkLogin() // 토큰이 설정 되면 로그인 상태 변경해준다
}
fun checkLogin(): Boolean {
with(context.getSharedPreferences(Constants.USER_TOKEN_PREF, Context.MODE_PRIVATE).getString(Constants.TOKEN_KEY, Constants.EMPTY_TOKEN)) {
if (this == Constants.EMPTY_TOKEN) return false else return true
}
return false
}
}
This is my test code
#RunWith(MockitoJUnitRunner::class)
class UserModelTest : InstrumentationTestCase() {
private val TEST_TOKEN_FROM_SERVER = "token"
#Mock
private lateinit var mockUserModel: User
private lateinit var realUserModel: User
var testContext = mock(Context::class.java)
#Before
fun initMocks() {
testContext = MockContext()
mockUserModel = User(testContext)
realUserModel = User(testContext)
given(realUserModel.tokenSharedPreferences.getString(eq(Constants.TOKEN_KEY), anyString()))
.willReturn(realUserModel.token)
}
}
I got "java.lang.IllegalStateException: context.getSharedPrefere…EF, Context.MODE_PRIVATE) must not be null" this error message.
Your code context.getSharedPreferences(Constants.USER_TOKEN_PREF, Context.MODE_PRIVATE) returns null so variable to store this value must be nullable:
var tokenSharedPreferences: SharedPreferences? =context.getSharedPreferences(Constants.USER_TOKEN_PREF, Context.MODE_PRIVATE)
SharedPrefManager.kt
class SharedPrefManager private constructor(context: Context) {
lateinit var mCtx: Context
fun isLoggedIn(): Boolean {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
if (sharedPreferences.getString(KEY_USERNAME, null) != null) {
return true
}
return false
}
fun username(): String {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
return sharedPreferences.getString(KEY_USERNAME, null)
}
fun userEmail(): String {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
return sharedPreferences.getString(KEY_USER_EMAIL, null)
}
init {
mCtx = context
}
fun userLogin(id: Int, username: String, email: String): Boolean {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putInt(KEY_USER_ID, id)
editor.putString(KEY_USER_EMAIL, email)
editor.putString(KEY_USERNAME, username)
editor.apply()
return true
}
fun logout(): Boolean {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.clear()
editor.apply()
return true
}
companion object {
lateinit var mInstance: SharedPrefManager
private val SHARED_PREF_NAME = "mysharedpref12"
private val KEY_USERNAME = "username"
private val KEY_USER_EMAIL = "useremail"
private val KEY_USER_ID = "userid"
#Synchronized
fun getInstance(context: Context): SharedPrefManager {
if (mInstance == null) {
line:59-----> mInstance = SharedPrefManager(context)
}
return mInstance
}
}
}
This is the error which i am getting
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.shikh.kotlinmysql, PID: 6600
kotlin.UninitializedPropertyAccessException: lateinit property mInstance has not been initialized
at com.example.shikh.kotlinmysql.SharedPrefManager$Companion.getMInstance(SharedPrefManager.kt:59)
at com.example.shikh.kotlinmysql.SharedPrefManager$Companion.getInstance(SharedPrefManager.kt:66)
at com.example.shikh.kotlinmysql.Login$userLogin$stringRequest$2.onResponse(Login.kt:34)
at com.example.shikh.kotlinmysql.Login$userLogin$stringRequest$2.onResponse(Login.kt:29)
Login.kt
class Login : AppCompatActivity() , View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
buttonLogIn.setOnClickListener(this)
}
private fun userLogin() {
val username = editTextUser.text.toString().trim()
val password = editTextPass.text.toString().trim()
line:29----> val stringRequest = object : StringRequest(Request.Method.POST, Constants.URL_LOGIN,
Response.Listener<String> { response ->
try {
val obj = JSONObject(response)
if (!obj.getBoolean("error")) {
line:34----> SharedPrefManager.getInstance(applicationContext).userLogin(
obj.getInt("id"),
obj.getString("username"),
obj.getString("email")
)
Toast.makeText(applicationContext, "User log in Succesful", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(applicationContext, obj.getString("message"), Toast.LENGTH_LONG).show()
}
} catch (e: JSONException) {
e.printStackTrace()
}
},
object : Response.ErrorListener {
override fun onErrorResponse(error: VolleyError) {
Toast.makeText(applicationContext, error.message, Toast.LENGTH_SHORT).show()
}
}) {
#Throws(AuthFailureError::class)
override fun getParams(): Map<String, String> {
val params = HashMap<String, String>()
params.put("username", username)
params.put("password", password)
return params
}
}
}
override fun onClick(v: View?) {
if (v==buttonLogIn){
userLogin()
}
}
}
If you're on Kotlin 1.2 you should check if mInstance is initialised like this:
if (!::mInstance.isInitialized) {
mInstance = SharedPrefManager(context)
}
i try to resolve memory leak in Shared Preferences use, i try all day to do this, but still confuse, my goal is possible call pref in anywhere i want. here my code.
class Preferences (private val context: Context) {
private val sharedPreferences: SharedPreferences =
context.getSharedPreferences(context.packageName+"_pref", Context.MODE_PRIVATE)
private val editor: SharedPreferences.Editor
companion object {
private val KEY_USER = "user"
private val KEY_EMAIL = "email"
}
init {
editor = sharedPreferences.edit()
}
private fun isKeyExist(Key: String): Boolean = sharedPreferences.contains(Key)
private fun putString(Key: String, value: String) {
editor.putString(Key, value)
editor.apply()
}
private fun putInt(Key: String, value: Int) {
editor.putInt(Key, value)
editor.apply()
}
private fun putBoolean(Key: String, value: Boolean) {
editor.putBoolean(Key, value)
editor.apply()
}
private fun putDouble(key: String, value: Double) {
editor.putLong(key, java.lang.Double.doubleToRawLongBits(value))
}
private fun getInt(Key: String): Int = sharedPreferences.getInt(Key, 0)
private fun getString(Key: String): String = sharedPreferences.getString(Key, "")
private fun getBoolean(key: String): Boolean = sharedPreferences.getBoolean(key, false)
private fun getLong(key: String): Long = sharedPreferences.getLong(key, 0)
fun init (){
if(!isKeyExist(KEY_USER)){
putString(KEY_USER,"")
}
if(!isKeyExist(KEY_EMAIL)){
putString(KEY_EMAIL,"")
}
}
private fun resetPref(){
if(isKeyExist(KEY_USER)){
putString(KEY_USER,"")
}
if(isKeyExist(KEY_EMAIL)){
putString(KEY_EMAIL,"")
}
}
var user : String
get() = getString(KEY_USER)
set(value) = putString(KEY_USER,value)
var email : String
get() = getString(KEY_EMAIL)
set(value) = putString(KEY_EMAIL,value)
Because pref need context, i init pref in some class with extend Application like code below,
class BaseApplication : android.app.Application() {
override fun onCreate() {
super.onCreate()
preferences = Preferences(applicationContext)
}
companion object {
#SuppressLint("StaticFieldLeak")
var preferences : Preferences? = null
}
with this method, it's possible to call pref anywhere like activity, fragment, or some class with no context, with this simple way,
BaseApplication.preferences!!.user
but it will make memory leak in my apps.
will appreciate if any someone can give me some advice how to resolve memory leak.
We call this use as a singleton pattern. Use this class :
public class Prefs {
private static final String TAG = "Prefs";
static Prefs singleton = null;
static SharedPreferences preferences;
static SharedPreferences.Editor editor;
private static Gson GSON = new Gson();
Type typeOfObject = new TypeToken<Object>() {
}.getType();
Prefs(Context context) {
preferences = context.getSharedPreferences(TAG, Context.MODE_PRIVATE);
editor = preferences.edit();
}
public static Prefs with(Context context) {
if (singleton == null) {
singleton = new Builder(context).build();
}
return singleton;
}
public void save(String key, boolean value) {
editor.putBoolean(key, value).apply();
}
public void save(String key, String value) {
editor.putString(key, value).apply();
}
public void save(String key, int value) {
editor.putInt(key, value).apply();
}
public void save(String key, float value) {
editor.putFloat(key, value).apply();
}
public void save(String key, long value) {
editor.putLong(key, value).apply();
}
public void save(String key, Set<String> value) {
editor.putStringSet(key, value).apply();
}
// to save object in prefrence
public void save(String key, Object object) {
if (object == null) {
throw new IllegalArgumentException("object is null");
}
if (key.equals("") || key == null) {
throw new IllegalArgumentException("key is empty or null");
}
editor.putString(key, GSON.toJson(object)).apply();
}
// To get object from prefrences
public <T> T getObject(String key, Class<T> a) {
String gson = preferences.getString(key, null);
if (gson == null) {
return null;
} else {
try {
return GSON.fromJson(gson, a);
} catch (Exception e) {
throw new IllegalArgumentException("Object storaged with key "
+ key + " is instanceof other class");
}
}
}
public boolean getBoolean(String key, boolean defValue) {
return preferences.getBoolean(key, defValue);
}
public String getString(String key, String defValue) {
return preferences.getString(key, defValue);
}
public int getInt(String key, int defValue) {
return preferences.getInt(key, defValue);
}
public float getFloat(String key, float defValue) {
return preferences.getFloat(key, defValue);
}
public long getLong(String key, long defValue) {
return preferences.getLong(key, defValue);
}
public Set<String> getStringSet(String key, Set<String> defValue) {
return preferences.getStringSet(key, defValue);
}
public Map<String, ?> getAll() {
return preferences.getAll();
}
public void remove(String key) {
editor.remove(key).apply();
}
public void removeAll() {
editor.clear();
editor.apply();
}
private static class Builder {
private final Context context;
public Builder(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null.");
}
this.context = context.getApplicationContext();
}
/**
* Method that creates an instance of Prefs
*
* #return an instance of Prefs
*/
public Prefs build() {
return new Prefs(context);
}
}
}
The kotlin version:
class Prefs internal constructor(context: Context) {
internal var typeOfObject = object : TypeToken<Any>() {
}.type
val all: Map<String, *>
get() = preferences.all
init {
preferences = context.getSharedPreferences(TAG, Context.MODE_PRIVATE)
editor = preferences.edit()
}
fun save(key: String, value: Boolean) {
editor.putBoolean(key, value).apply()
}
fun save(key: String, value: String) {
editor.putString(key, value).apply()
}
fun save(key: String, value: Int) {
editor.putInt(key, value).apply()
}
fun save(key: String, value: Float) {
editor.putFloat(key, value).apply()
}
fun save(key: String, value: Long) {
editor.putLong(key, value).apply()
}
fun save(key: String, value: Set<String>) {
editor.putStringSet(key, value).apply()
}
// to save object in prefrence
fun save(key: String?, `object`: Any?) {
if (`object` == null) {
throw IllegalArgumentException("object is null")
}
if (key == "" || key == null) {
throw IllegalArgumentException("key is empty or null")
}
editor.putString(key, GSON.toJson(`object`)).apply()
}
// To get object from prefrences
fun <T> getObject(key: String, a: Class<T>): T? {
val gson = preferences.getString(key, null)
return if (gson == null) {
null
} else {
try {
GSON.fromJson(gson, a)
} catch (e: Exception) {
throw IllegalArgumentException("Object storaged with key "
+ key + " is instanceof other class")
}
}
}
fun getBoolean(key: String, defValue: Boolean): Boolean {
return preferences.getBoolean(key, defValue)
}
fun getString(key: String, defValue: String): String? {
return preferences.getString(key, defValue)
}
fun getInt(key: String, defValue: Int): Int {
return preferences.getInt(key, defValue)
}
fun getFloat(key: String, defValue: Float): Float {
return preferences.getFloat(key, defValue)
}
fun getLong(key: String, defValue: Long): Long {
return preferences.getLong(key, defValue)
}
fun getStringSet(key: String, defValue: Set<String>): Set<String>? {
return preferences.getStringSet(key, defValue)
}
fun remove(key: String) {
editor.remove(key).apply()
}
fun removeAll() {
editor.clear()
editor.apply()
}
private class Builder(context: Context?) {
private val context: Context
init {
if (context == null) {
throw IllegalArgumentException("Context must not be null.")
}
this.context = context.applicationContext
}
/**
* Method that creates an instance of Prefs
*
* #return an instance of Prefs
*/
fun build(): Prefs {
return Prefs(context)
}
}
companion object {
private val TAG = "Prefs"
lateinit var singleton: Prefs
lateinit var preferences: SharedPreferences
lateinit var editor: SharedPreferences.Editor
private val GSON = Gson()
fun with(context: Context): Prefs {
if (singleton == null) {
singleton = Builder(context).build()
}
return singleton
}
}
}
You will need google GSON to save objects.
Calling it is like this :
Prefs.with(context).save("key","value or object or int or boolean");
Hope this helps.