Rapidly fast and lightweight re-implementation of SharedPreferences which stores each preference in files separately, performs disk operations via NIO with memory mapped byte buffers and works IPC (between processes). Written from scratch.
Rapidly fast and lightweight re-implementation of SharedPreferences
which stores each preference in files separately, performs disk operations
via NIO with memory mapped byte buffers and works IPC (between processes).
Written from scratch.
SharedPreferences
interfacedouble
, char
, short
and byte
Persistable
classAdd jitpack to repositories closure. For example, you should add it to root
of build.gradle
:
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
Add dependency:
dependencies {
compile "com.github.yandextaxitech:binaryprefs:$version"
}
Preferences preferences = new BinaryPreferencesBuilder(context)
.build();
Please, use only one instance of preferences by name, it saves you from
non-reasoned allocations. You can store one preferences instance in
application class, factory or even better just use one instance from IoC
like Dagger or use another DI framework.
All parameters optional and chain-buildable.
Builder contains method which is defines desirable preferences name:
Preferences preferences = new BinaryPreferencesBuilder(context)
.name("user_data")
.build();
Default is “default” name.
You can add the following extensions for use Binary Pref in Kotlin DSL:
fun Preferences.commit(block: PreferencesEditor.() -> Unit) {
val editor = this.edit()
block(editor)
editor.commit()
}
fun Preferences.apply(block: PreferencesEditor.() -> Unit) {
val editor = this.edit()
block(editor)
editor.apply()
}
pref.commit {
putString(KEY_STRING, "<String value>")
putInt(KEY_INT, 0)
}
You can define your own key/value vice versa encryption or use default:
Preferences preferences = new BinaryPreferencesBuilder(context)
.keyEncryption(new XorKeyEncryption("16 bytes secret key".getBytes())))
.valueEncryption(new AesValueEncryption("16 bytes secret key".getBytes(), "16 bytes initial vector".getBytes()))
.build();
Default is no-op encryption for key and value.
You can listen exceptions which throws during disk IO, serialization,
task execution operations:
Preferences preferences = new BinaryPreferencesBuilder(context)
.exceptionHandler(new ExceptionHandler() {
@Override
public void handle(Exception e) {
//perform analytics report
}
}).build();
Default is print handler which performs e.printStacktrace()
when
exception event occurs.
You can save preferences into an custom directory:
Preferences preferences = new BinaryPreferencesBuilder(context)
.customDirectory(Environment.getExternalStorageDirectory())
.build();
Be careful: writing into external directory required appropriate
runtime and manifest permissions.
If your app architecture is process based (services works in separate processes)
and you would like to get preferences updates with consistent cache state
you can enable this feature:
Preferences preferences = new BinaryPreferencesBuilder(context)
.supportInterProcess(true)
.build();
Please, note that one key change delta should be less than 1 (one) megabyte
because IPC data transferring is limited by this capacity.
Details here: Documentation
Persistable
Persistable
contract been added for fast and flexible saving and it’s
restoring complex objects. It’s pretty similar like standard java
Externalizable
but without few methods which don’t need for.
For usage you just need to implement this interface with methods in your
data-model.
All top level Persistable data-objects should be registered by key for
understanding de/serialization contract during cache initialization.
Persistable
Preferences preferences = new BinaryPreferencesBuilder(context)
.registerPersistable(TestUser.KEY, TestUser.class)
.registerPersistable(TestOrder.KEY, TestOrder.class)
.build();
Note about deepClone
method: you should implement full object hierarchy copying
for fast immutable in-memory data fetching. Main proposes for this method is local
object mutability instead in-memory cache mutability.
But if your data class immutable and you define all values from constructor you just
can return this
from method.
Sample for explanation: TestUser.java
P.S.:
If you have group of preferences which always stores under one transaction and you want
to reduce disk IO just use Persistable for storing this bulk as close as possible.
Builder have simple api for existing preferences migration:
Preferences preferences = new BinaryPreferencesBuilder(context)
.migrateFrom(oldPreferences)
.migrateFrom(oldPreferences2)
.build();
You can append one or more preferences for migration and all will be merged into
this one implementation.
After successful migration all data in migrated preferences will be removed.
Please note that all existing values in this implementation will be rewritten
to values which migrates into.
Also type information will be rewritten and lost too without any exception.
If this method will be called multiple times for two or more different instances
of preferences which has keys collision then last preferences values will be applied.
You can dump your preferences with adb console command right in logcat:
adb shell am broadcast -a com.ironz.binaryprefs.ACTION_DUMP_PREFERENCE --es "pref_name" "your_pref_name" (optional: --es "pref_key" "your_pref_key")
where:
your_pref_name
- is your preferences name which is defined in register
method.
your_pref_key
- is your preference key, this is optional value.
How to register preferences by name:
DumpReceiver.register(name, preferences);
Fully working example of all values dump:
adb shell am broadcast -a com.ironz.binaryprefs.ACTION_DUMP_PREFERENCE --es "pref_name" "user_data"
Example only for user_id
key dump:
adb shell am broadcast -a com.ironz.binaryprefs.ACTION_DUMP_PREFERENCE --es "pref_name" "user_data" --es "pref_key" "user_id"
Please note that if you create multiple instances of one preferences
(e.g. in Activity#onCreate
) you should unregister dump
(e.g. in Activity#onDestroy
) like this:
DumpReceiver.unregister(name);
Persistable
LockFactory
.byte[]
supportsun.misc.Unsafe
serialization mode for api 21+Copyright 2017 Alexander Efremenkov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.