chibatching / kotpref Goto Github PK
View Code? Open in Web Editor NEWKotpref - Android SharedPreferences delegation library for Kotlin
Home Page: https://chibatching.github.io/Kotpref/
License: Apache License 2.0
Kotpref - Android SharedPreferences delegation library for Kotlin
Home Page: https://chibatching.github.io/Kotpref/
License: Apache License 2.0
It is possible to use rxjva to be notified when one preference change?
I've tried to test method with Kotpref line UserCredentialsPref.username
but I've always got same error java.lang.IllegalStateException: Kotpref has not been initialized.
Unlike all the Prefs that extend AbstractPref
, such as StringPref
or IntPref
: StringSetPref
has a memory cache of the value that it represents, instead of fetching from the SharedPreferences
when requested.
So when implementing a xml preference, as seen in #47. The value of the StringSetPref
isn't updated when a user makes changes via a PreferenceFragment
.
A work-around is to perform a beginBulkEdit()
and then cancelBulkEdit()
in sequence before reading these values.
The problems lies in the getValue
method of the StringSetPref
class, as seen here:
override operator fun getValue(thisRef: KotprefModel, property: KProperty<*>): MutableSet<String> {
if (stringSet == null || lastUpdate < thisRef.kotprefTransactionStartTime) {
val prefSet = thisRef.kotprefPreference.getStringSet(key ?: property.name, null)
?.let { HashSet(it) }
stringSet = PrefMutableSet(
thisRef,
prefSet ?: default.invoke().toMutableSet(),
key ?: property.name
)
lastUpdate = SystemClock.uptimeMillis()
}
return stringSet!!
}
One way of fixing it would be to replace the content of the stringSet: MutableSet<String>?
when reading the value, and removing the if
condition. Something like this:
override operator fun getValue(thisRef: KotprefModel, property: KProperty<*>): MutableSet<String> {
val prefSet = thisRef.kotprefPreference.getStringSet(key ?: property.name, null)
?.let { HashSet(it) }
stringSet = stringSet?.apply {
//TODO Update its content with prefSet without triggering preference file editing
} ?: PrefMutableSet(
thisRef,
prefSet ?: default.invoke().toMutableSet(),
key ?: property.name)
return stringSet!!
}
Just wondering If any method you can provide from which I can remove all saved preference values?
Thanks, Your library is Awesome!!
We have a lot of code that depends in kotpref.
And we have also many unitTests.
Majority of them do not use android emulator or context to be as fast as possible.
As is, we can not instantiate kotpref, and so we need to put if's in all place to only see preference's if we are not unit testing so that will not break.
Could kotpref have an boolean option to set it for unit testing = true.
In that option, it only return the setted preference value, but not save it to android preferences?
That would be great!
Hello.
Gradle was unable to download com.chibatching.pref:pref:2.0.0
for me. changing to com.chibatching.kotpref:kotpref:2.0.0
helped. Have not checked whether other modules of library act like this or not.
http://jcenter.bintray.com/com/chibatching/kotpref/kotpref/2.0.0/
As of now, there is no support for versioning of KotprefModel. This is useful in some cases when someone wants to remove a key on version update, or clear the complete model itself.
This could be provided by having a version number in KotprefModel and calling an abstract function onVersionUpdate
whenever the version number is increased.
It's not yet possible to remove an entry from the shared preferences. Would be nice if this works.
Hello.
I've noticed that all mutating operations on a set are being applied immediately, e. g.
val result = set.add(element)
kotprefModel.kotprefPreference.edit().putStringSet(key, set).apply()
return result
but iterator()
funciton just returns undecorated set.iterator()
, and it's easy to call remove()
on it without triggering SharedPreferences update.
Am I right? Will this be fixed? Do you need help with it?
Hi would it be possible to add support for double data type?
Unlike all the Prefs that extend AbstractPref
, such as StringPref
or IntPref
: StringSetPref
has a memory cache of the value that it represents, instead of fetching from the SharedPreferences
when requested.
So when implementing a xml preference, as seen in #47. The value of the StringSetPref
isn't updated when a user makes changes via a PreferenceFragment
.
A work-around is to perform a beginBulkEdit()
and then cancelBulkEdit()
in sequence before reading these values.
The problems lies in the getValue
method of the StringSetPref
class, as seen here:
override operator fun getValue(thisRef: KotprefModel, property: KProperty<*>): MutableSet<String> {
if (stringSet == null || lastUpdate < thisRef.kotprefTransactionStartTime) {
val prefSet = thisRef.kotprefPreference.getStringSet(key ?: property.name, null)
?.let { HashSet(it) }
stringSet = PrefMutableSet(
thisRef,
prefSet ?: default.invoke().toMutableSet(),
key ?: property.name
)
lastUpdate = SystemClock.uptimeMillis()
}
return stringSet!!
}
One way of fixing it would be to replace the content of the stringSet: MutableSet<String>?
when reading the value, and removing the if
condition. Something like this:
override operator fun getValue(thisRef: KotprefModel, property: KProperty<*>): MutableSet<String> {
val prefSet = thisRef.kotprefPreference.getStringSet(key ?: property.name, null)
?.let { HashSet(it) }
stringSet = stringSet?.apply {
//TODO Update its content with prefSet without triggering preference file editing
} ?: PrefMutableSet(
thisRef,
prefSet ?: default.invoke().toMutableSet(),
key ?: property.name)
return stringSet!!
}
Hi, i am getting this error
java.lang.NoClassDefFoundError: at com.chibatching.kotpref.initializer.KotprefInitProvider.onCreate (KotprefInitProvider.kt:20) at android.content.ContentProvider.attachInfo (ContentProvider.java:1638) at android.content.ContentProvider.attachInfo (ContentProvider.java:1609) at android.app.ActivityThread.installProvider (ActivityThread.java:5008) at android.app.ActivityThread.installContentProviders (ActivityThread.java:4582) at android.app.ActivityThread.handleBindApplication (ActivityThread.java:4522) at android.app.ActivityThread.access$1500 (ActivityThread.java:151) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1381) at android.os.Handler.dispatchMessage (Handler.java:110) at android.os.Looper.loop (Looper.java:193) at android.app.ActivityThread.main (ActivityThread.java:5292) at java.lang.reflect.Method.invokeNative (Native Method) at java.lang.reflect.Method.invoke (Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:824) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:640) at dalvik.system.NativeStart.main (Native Method)
on phones with Android SDK 19 (KitKat 4.4). I am using com.chibatching.kotpref:initializer:2.5.0
As stated in the title.
I'm trying to perform a verification/assertion on the clear()
method of a KotprefModel
, and right now I have no way of doing so.
I don't think there are no drawbacks in opening the method, as I couldn't find any internal usage of the method.
Thanks again for the great library and support you are giving =)
I think it is not easy for users to recognize and remember this issue for preventing reset preferences. I hope to keep the preferences in a future version regardless of the KotprefModel object name change.
Hi and thanks for this beautifull library :)
Is it possible to add Double type ?
thanks
I have an XML preference
<ListPreference
android:id="@+id/pref_music_repeat"
android:defaultValue="0"
android:entries="@array/Replay_arrays"
android:entryValues="@array/array_repeat_value"
android:icon="@drawable/ic_pref_time"
android:key="key_music_repeat"
android:summary="%s"
android:title="Repeat Count" />
How can i use this in Kotpref
AndroidX Security introduces EncryptedSharedPreferences.
https://developer.android.com/topic/security/data.md
In past days, there were some encryption support request issues. But I was refusing it because of no existence of official SharedPreferences encryption support.
But it is time to support!
What's the best way to save hour without date using Kotpref? Only hour and minutes, without specific date?
Should I save hour and minutes seperately? And how to get it later as perhaps Date object?
In #88, gson support module uses gson TypeToken to support generics type.
We need some test for it, List or Map etc...
Adding a listener so something can be notified when a preference is changed seems like common behavior, but I can't find a way to do so easily.
The SharedPreferences
instance is internal to KotPrefModel
, so using OnSharedPreferenceChangeListener
requires actually getting the sharedPrefs object based on the class name, which you'd need to calculate yourself or hardcode.
Exposing the sharedPreferences
object in KotprefModel
would be an easy solution to this. Another would be writing your own wrapper for listeners.
Introduce from API level 26 or support library 26.0.0.
To support, we should consider how to handle initialize function according to api version or support lib dependency
I might be missing something but as far as i can tell there is no way to currently add a parcelable object.
Is it supported currently and if not are there any plans to add support for it?
Thankyou for such a wonderful library. Using it in many of my projects.
in many cases app might need commit for some properties.
commit/apply doesn't much depend on scenario, those rather depend on property.
we can use blockingCommit but adding blockingCommit every time we access that property is difficult.
i am added default commit support in my project. i can create a pull request, if you are ok with that. If there are any pitfalls please let me know.
This is how i did it.
internal class StringPref(val default: String, val key: String?, private val commitByDefault: Boolean)
override fun setToPreference(property: KProperty<*>, value: String, preference: SharedPreferences) {
preference.edit().putString(key ?: property.name, value).execute(commitByDefault)
}
fun SharedPreferences.Editor.execute(commit : Boolean) {
if(commit)
commit()
else
apply()
}
protected open val commitAllPropertiesByDefault: Boolean = false
protected fun stringPref(default: String = "", key: String? = null, commitByDefault : Boolean = commitAllPropertiesByDefault)
: ReadWriteProperty<KotprefModel, String> = StringPref(default, key, commitByDefault)
I have done these for json, enum projects as well
Let me know if there are any changes i need to do.
Hello. Thank you for a great library!
I need a way to commit()
some changes instead of apply()
ing them to save some crash information and exit immediately in my uncaught exception handler.
Here is my implementation: #22
Great library!
Could you please create an artifact also for moshi support? (https://github.com/square/moshi)
I believe it would be easy to add this starting from the gson-support code. Moshi is very similar to gson.
Thanks!
I use your library and it seems a proper way to work with preferences from Kotlin.
However I found one disadvantage: it is not possible to put the null value to a preference (see example bellow). In origin Android preference model I can do it through the Editor interface. In this case, when I read this property, I retrieve null or default value (if specified).
public object DevicePreference : KotprefModel() {
var key: String? by stringPrefVar(default = "")
}
In current case I should to write uncomfortable setting code:
string: String? = ""
DevicePreference.key = string ?: ""
I think that you should allow to set the null value to a preference. In this case it less comfortable to read value (need to add "!!" symbols) but users should chose preferable way by yourself.
It would be extremely useful for fully reactive apps to get a stream of preference changes.
Hi, this is a great open library
but, will it support encryption?
That must be better
I already add "compile 'com.chibatching:kotpref:1.4.0'" to app level gradle, but I cannot find KotprefModel() cunstructor in project. any suggest?
Why double isn't supported?
How about an extra module to create a preference screen for a KotprefModel
? Would be a very useful addition.
I've done smoething like this for my own KotprefModule
, could share the code with you so that you could derive a generic solution for this. Let me know if you're interested
I have a DropDownPreference with integer values. Android needs string-array for values to be used and that crates an issue where I have to define preference model member as var myPref: String by stringPref
.
Is there a correct way of of accessing this preference apart from converting it to Int in my code?
It will be nice to be available to use
var availableOfferList: List<OfferItem> by gsonPref(Collections.emptyList())
or
var offerDetails: Map<Long, OfferDetails> by gsonPref(Collections.emptyMap())
Maybe adding something like that to KotprefModel
:
publlic fun set(field: String, supportedType: SupportedTypeComesHere) {
...
}
and a get for each type.
System.currentTimeMillis()
is not monotone, is't better to use SystemClock.uptimeMillis()
for such a purpose.
i want to clear all data saved in pref, how to do it ?
class ProductLocal(context: Context) : KotprefModel() {
var productMap by gsonPref(HashMap<String,String>())
var productContentsMap by gsonPref(ConcurrentHashMap<String,String>())
}
I have tried both and none of them works. Am I missing anything here?
productLocal.productContentsMap.putAll ()
After updating to kotpref 2.1.0 and Kotlin 1.1.1 my UI-Tests fail with:
E/AndroidRuntime( 7659): Process: org.ligi.gobandroid_hd, PID: 7659
E/AndroidRuntime( 7659): java.lang.NoClassDefFoundError: com.chibatching.kotpref.KotprefPreferences$KotprefEditor$apply$1
E/AndroidRuntime( 7659): at com.chibatching.kotpref.KotprefPreferences$KotprefEditor.apply(KotprefPreferences.kt:21)
E/AndroidRuntime( 7659): at com.chibatching.kotpref.KotprefModel.commitBulkEdit(KotprefModel.kt:199)
E/AndroidRuntime( 7659): at org.ligi.gobandroid_hd.ui.game_setup.GameSetupFragment.refresh_ui(GameSetupFragment.kt:151)
E/AndroidRuntime( 7659): at org.ligi.gobandroid_hd.ui.game_setup.GameSetupFragment.onProgressChanged(GameSetupFragment.kt:80)
E/AndroidRuntime( 7659): at android.widget.SeekBar.onProgressRefresh(SeekBar.java:91)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.doRefreshProgress(ProgressBar.java:655)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.refreshProgress(ProgressBar.java:667)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.setProgress(ProgressBar.java:714)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.setProgress(ProgressBar.java:695)
E/AndroidRuntime( 7659): at org.ligi.gobandroid_hd.ui.game_setup.GameSetupFragment.refresh_ui(GameSetupFragment.kt:109)
E/AndroidRuntime( 7659): at org.ligi.gobandroid_hd.ui.game_setup.GameSetupFragment.onProgressChanged(GameSetupFragment.kt:80)
E/AndroidRuntime( 7659): at android.widget.SeekBar.onProgressRefresh(SeekBar.java:91)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.doRefreshProgress(ProgressBar.java:655)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.refreshProgress(ProgressBar.java:667)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.setProgress(ProgressBar.java:714)
E/AndroidRuntime( 7659): at android.widget.ProgressBar.setProgress(ProgressBar.java:695)
E/AndroidRuntime( 7659): at org.ligi.gobandroid_hd.ui.game_setup.GameSetupFragment.refresh_ui(GameSetupFragment.kt:105)
E/AndroidRuntime( 7659): at org.ligi.gobandroid_hd.ui.game_setup.GameSetupFragment.onStart(GameSetupFragment.kt:66)
E/AndroidRuntime( 7659): at android.support.v4.app.Fragment.performStart(Fragment.java:2218)
E/AndroidRuntime( 7659): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1340)
E/AndroidRuntime( 7659): at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528)
E/AndroidRuntime( 7659): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595)
E/AndroidRuntime( 7659): at android.support.v4.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:2907)
E/AndroidRuntime( 7659): at android.support.v4.app.FragmentController.dispatchStart(FragmentController.java:212)
E/AndroidRuntime( 7659): at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:613)
E/AndroidRuntime( 7659): at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
E/AndroidRuntime( 7659): at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
E/AndroidRuntime( 7659): at android.app.Activity.performStart(Activity.java:5241)
E/AndroidRuntime( 7659): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2168)
E/AndroidRuntime( 7659): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
E/AndroidRuntime( 7659): at android.app.ActivityThread.access$800(ActivityThread.java:135)
E/AndroidRuntime( 7659): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
E/AndroidRuntime( 7659): at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime( 7659): at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime( 7659): at android.app.ActivityThread.main(ActivityThread.java:5017)
E/AndroidRuntime( 7659): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 7659): at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime( 7659): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
E/AndroidRuntime( 7659): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
E/AndroidRuntime( 7659): at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager( 1549): Force-killing crashed app org.ligi.gobandroid_hd at watcher's request
will have to digg a bit deeper - but dropping this here now as I guess the root is in kotpref and you might see whats wrong in a glance without digging.
gradle
implementation 'com.chibatching.kotpref:kotpref:2.9.1'
implementation 'androidx.lifecycle:lifecycle-livedata:2.0.0'
implementation "org.jetbrains.kotlin:kotlin-reflect:1.3.41"
my user data is
object User :KotprefModel(){
var username by stringPref()
var token by stringPref()
var uid by intPref()
var isLogin by booleanPref()
val isLogined = User.asLiveData(User::isLogin)//highlight code
}
my fragment
class FragmentTwo : BaseFragment() {
companion object {
fun newInstance() = FragmentTwo()
}
private val viewModel by lazy { ViewModelProviders.of(requireActivity()).get(FragmentTwoViewModel::class.java) }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_two_fragment, container, false)
val bind = DataBindingUtil.bind<FragmentTwoFragmentBindingImpl>(view)
bind?.lifecycleOwner = this
bind?.twoVm = viewModel
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// TODO: Use the ViewModel
viewModel.isStart.observe(this, Observer {
startActivity(Intent(context,it.first))
})
//highlight code
User.isLogined.observe(this, Observer {
Log.d(javaClass.name,"asLiveData(User::isLogin) $it")
})
}
}
when i wanna change isLogin
in this method
User.isLogin = true
fragment observe is not called
when i change extend code
KotprefModel.asLiveData
remove this@asLiveData.preferences.unregisterOnSharedPreferenceChangeListener(this)
the observe is working.
I think there is some issue in KotprefModel.asLiveData
Hey there! Was just browsing through possible libraries to use to simplify interactions with SharedPreferences
while using Kotlin and found yours.
Are there any plans on supporting enum storage while allowing customization between storage as a string or an integer from an ordinal? If you already have something in the works, that's great. If not, I could gladly contribute support for it to this library.
Hello again :)
What about supporting pref values, which could be presisted into String by custom converter?
object AppState { // client code
val user by customPref<User?>(default = null, converter = UserConverter)
}
interface PrefConverter<T> { // library code
fun fromPref(str: String): T
fun toPref(t: T): String
}
object UserConverter : PrefConverter<User> { // client code
private val gson = Gson()
override fun fromPref(str: String) = gson.fromJson(str, User::class.java)
override fun toPref(t: T) = gson.toJson(t)
}
Many ORMs (Hibernate, GreenDAO, ORMLite, ObjectBox, etc) do this for object's fields, so we can borrow some architectural solutions from them.
Pleeease release a new version to support:
androidx.security.crypto.EncryptedSharedPreferences
Let the app decide using PreferencesOpener
From local machine works fine with the same command
Line 57 in 592f909
Only sources.jar file is uploaded, not javadoc.jar, aar and pom.xml
On button press I add some string to set and then print all
UserData.enabledPeers.add(userId);
UserData.enabledPeers.forEach {
Log.e("Enabled peers", it)
}
New string is here.
Then I kill process (swipe out from recents), launch it and print again.
New string isn't here anymore =(
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.