Code Monkey home page Code Monkey logo

binaryprefs's Introduction

Build Status API Android Arsenal

Binary Preferences

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.

Advantages

  • Lightweight. Zero dependency
  • Super fast (faster than most other key/value solutions)
  • Small memory footprint while serialize/deserialize data
  • Zero copy in-memory cache
  • Persists only binary data. Not XML or JSON
  • Out of box data encryption support
  • Fully backward compatible with default SharedPreferences interface
  • Store all primitives include double, char, short and byte
  • Store complex data objects backward-compatible (see Persistable class documentation)
  • IPC support (preferences change listeners and in-memory cache works between processes)
  • Handle various exception events

Usage

Add in project

Add 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"
}

Minimal working configuration

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.

Custom preferences name

Builder contains method which is defines desirable preferences name:

Preferences preferences = new BinaryPreferencesBuilder(context)
                .name("user_data")
                .build();

Default is "default" name.

Kotlin usage.

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()
}
Sample of kotlin code with extensions:
pref.commit {
    putString(KEY_STRING, "<String value>")
    putInt(KEY_INT, 0)
}

Encryption

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.

Exception handler

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.

Custom save directory

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.

IPC mode

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

Dealing with 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.

How to register 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.

Migration from another implementations

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.

Logcat preferences dump

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);

Roadmap

  1. Disk I/O encrypt. completed
  2. IPC completed
  3. Externalizable. completed as Persistable
  4. Preferences tooling (key set reading). implemented
  5. Custom serializers. completed
  6. Synchronous commits. completed
  7. Store all primitives (like byte, short, char, double). completed
  8. Lock free (avoid locks). completed as LockFactory.
  9. Exact background tasks for each serialization strategies. completed
  10. Reduce events (implement events transaction). completed.
  11. Simplify api (instance creating, exception handles). completed
  12. File name encrypt completed
  13. Finalize serialization and persistence contract completed
  14. Default preferences migration mechanism complete
  15. In-memory cache initialization strategies
  16. byte[] support
  17. IPC transactions without 1mb limit temporary impossible due to major ashmem changes between Android runtime versions
  18. RxJava support Please, use: https://github.com/f2prateek/rx-preferences
  19. sun.misc.Unsafe serialization mode for api 21+ - not actual due to private api usage is limited at runtime.
  20. Limiting strategies (UNLIMITED, LRU, FIFO)

License

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.

binaryprefs's People

Contributors

achernoprudov avatar acmi avatar fi5t avatar iamironz avatar iismagilov avatar lion4ik avatar samiuelson avatar sboishtyan avatar vkotovv avatar vovastelmashchuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

binaryprefs's Issues

Support for Lists, Sets and Arrays

Are there any plans to add support for Lists, Set and / or arrays? Would be a nice additional feature for this library. Would you accept a pull request if I would implement this?

From a quick overview from the code I think only the Serializer and their SerializationStrategy needs to be reimplemented for this so it shouldn't be too hard.

editor.clear() not clears prefs

Hi!

SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.commit();

Not clears anything in my case, maybe some issues with threads, but calling editor.remove("some_string") for every preference do the job

Can't create preferences directory in /mnt/expand/

Library version: 1.0.1
Android version: 6.0, 6.01, 7.1.1, 8.10
Devices: Many different vendors

RuntimeException: Unable to create service due to error : Can't create definition for 'Single [name='e',class='com.ironz.binaryprefs.e']' due to error : Can't create preferences directory in /mnt/expand/48c4be18-bd88-491e-a0ac-d6aaedfe1df9/user/0/info.dvkr.screenstream/files/preferences/default/values com.ironz.binaryprefs.e.b.a.a(AndroidDirectoryProvider.java:40) com.ironz.binaryprefs.e.b.a.<init>(AndroidDirectoryProvider.java:31) com.ironz.binaryprefs.b.b(BinaryPreferencesBuilder.java:1266)

Common thins is that directory starts from: /mnt/expand/

Incorrect state of contains method of BinaryPrefs after creation

When I create new instance of binary prefs contains(String) method work incorrect:

final SharedPreferences sharedPreferences = prefsProvider.providePrefs(prefsName);
if (sharedPreferences == null) {
	return;
}

Log.d("PrefsTest", "binaryPrefs contains " + key +":" + sharedPreferences.contains(key));
if (!sharedPreferences.contains(key)) {
	Log.d("PrefsTest", "print all prefs: " + sharedPreferences.getAll());
	Log.d("PrefsTest", "binaryPrefs contains " + key +":" + sharedPreferences.contains(key));
	if (!sharedPreferences.contains(key)) {
		return;
	}
}

PrefsProvider create new instance of binary prefs.

After calling this code you can see next logs:

binaryPrefs contains application_id:false
PrefsTest: print all prefs: {application_id=XXXXX}
binaryPrefs contains application_id:true

When I was calling sharedPreferences.getAll() method, sharedPreferences.contains start work correct

🐞Bug with encryption

I faced a strange bug when tried to work with two instances of this shared preferences. I use Tink as an encryption engine with your library and want to show you some unexcepted behavior when they work together.

P.S. Sorry for the Kotlin :D

        try {
            TinkConfig.register()
        } catch (e: GeneralSecurityException) {
            throw RuntimeException(e)
        }

        val keysetHandle = AndroidKeysetManager.Builder()
            .withSharedPref(this, KEYSET_NAME, PREFERENCE_FILE)
            .withKeyTemplate(AeadKeyTemplates.AES256_GCM)
            .withMasterKeyUri(MASTER_KEY_URI)
            .build()
            .keysetHandle

        val aead = AeadFactory.getPrimitive(keysetHandle)

        val bpInstance1 = BinaryPreferencesBuilder(this)
            .name("main_file")
            .valueEncryption(TinkValueEncryption(aead, "good_data".toByteArray()))
            .build()

        val bpInstance2 = BinaryPreferencesBuilder(this)
            .name("main_file")
            .valueEncryption(TinkValueEncryption(aead, "bad_data".toByteArray()))
            .build()

        bpInstance1.edit {
            putString("my_key", "bug")
        }

        val result = bpInstance2.getString("my_key", "no bug")

I expect to see "GeneralSecurityException" or "no_bug" in the result variable, but I see "bug" there. It's wrong behavior, because I set the different associated data for each instance. Any ideas?

I've prepared a repository to reproduce this bug. Please, check it out and tell me where I was wrong =)

Create a ktx module

What do you think about create ktx module for library?
For distribution method from readMe and other kotlin stuff, like a delegate for SharedPreferences

RuntimeException: Unable to start receiver com.ironz.binaryprefs.dump.DumpReceiver

Library version: 1.0.1
Android version: 5.0.2 (Looks like only on this version)
Devices: Defy Mini, Batmobile XT320

`Exception: java.lang.RuntimeException: Unable to start receiver com.ironz.binaryprefs.dump.DumpReceiver: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2586)
at android.app.ActivityThread.access$1700(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1355)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:746)
at java.util.concurrent.ConcurrentHashMap.containsKey(ConcurrentHashMap.java:774)
at com.ironz.binaryprefs.dump.DumpReceiver.onReceive(DumpReceiver.java:25)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2579)
at android.app.ActivityThread.access$1700(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1355)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
`

Crashes when using same preferences in different applications

I have a pool of apps and try to share data between them.

Binaryprefs uses in the library for sharing codebase between apps. So dependency ladder looks like
binaryprefs -> lib -> app1
binaryprefs -> lib -> app2

build.gradle (module lib):
compile "com.github.iamironz:binaryprefs:1.0.0-BETA-2"

creating instance in lib:

public class BinaryPreferenceHelper {

    private static final String PREF_NAME = "intercom_options";
    private static final String DIRECTORY_PATH = "dnake/cfg";

    public static Preferences getPreferencesInstance(Context context){
        return new BinaryPreferencesBuilder(context)
                .name(PREF_NAME)
                .customDirectory(new File(DIRECTORY_PATH))
                .keyEncryption(KeyEncryption.NO_OP)
                .valueEncryption(ValueEncryption.NO_OP)
                .supportInterProcess(true)
                .build();

    }
}

instances init in app1 and app2 classes like this:

public class DesktopApp extends Application {

    private static Preferences sSetting;

    public static Preferences getSetting() {
        return sSetting;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        sSetting = BinaryPreferenceHelper.getPreferencesInstance(this);

    }
}

using in apps like this:
mIsUnit = IntercomOptions.MonitorMode.get(TalkApp.getSetting());

where

public static class MonitorMode {
        public static boolean get(Preferences preferences) {
            return preferences.getBoolean("pref_monitor_mode", false);
        }

        public static void set(Preferences preferences, boolean isUnit) {
            preferences.edit().putBoolean("pref_monitor_mode", isUnit).apply();
        }
    }

and if I open firs app everything is ok, but when I run second, I'll get a crash:
java.lang.RuntimeException: Unable to create application com.dnake.talk.TalkApp: com.ironz.binaryprefs.exception.FileOperationException: java.util.concurrent.ExecutionException: com.ironz.binaryprefs.exception.FileOperationException: java.io.FileNotFoundException: /dnake/cfg/preferences/intercom_options/values/pref_monitor_mode: open failed: EACCES (Permission denied) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4347) at android.app.ActivityThread.access$1500(ActivityThread.java:135) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5017) 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:779) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) at dalvik.system.NativeStart.main(Native Method) Caused by: com.ironz.binaryprefs.exception.FileOperationException: java.util.concurrent.ExecutionException: com.ironz.binaryprefs.exception.FileOperationException: java.io.FileNotFoundException: /dnake/cfg/preferences/intercom_options/values/pref_monitor_mode: open failed: EACCES (Permission denied) at com.ironz.binaryprefs.task.FutureBarrier.completeBlockingUnsafe(FutureBarrier.java:44) at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:52) at com.ironz.binaryprefs.BinaryPreferences.<init>(BinaryPreferences.java:40) at com.ironz.binaryprefs.BinaryPreferencesBuilder.createInstance(BinaryPreferencesBuilder.java:251) at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:226) at com.basip.intercom.binary.BinaryPreferenceHelper.getPreferencesInstance(BinaryPreferenceHelper.java:25) at com.dnake.talk.TalkApp.onCreate(TalkApp.java:20) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344) at android.app.ActivityThread.access$1500(ActivityThread.java:135)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:136)  at android.app.ActivityThread.main(ActivityThread.java:5017)  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:779)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)  at dalvik.system.NativeStart.main(Native Method)  Caused by: java.util.concurrent.ExecutionException: com.ironz.binaryprefs.exception.FileOperationException: java.io.FileNotFoundException: /dnake/cfg/preferences/intercom_options/values/pref_monitor_mode: open failed: EACCES (Permission denied) at java.util.concurrent.FutureTask.report(FutureTask.java:93) at java.util.concurrent.FutureTask.get(FutureTask.java:163) at com.ironz.binaryprefs.task.FutureBarrier.completeBlockingUnsafe(FutureBarrier.java:42) at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:52)  at com.ironz.binaryprefs.BinaryPreferences.<init>(BinaryPreferences.java:40)  at com.ironz.binaryprefs.BinaryPreferencesBuilder.createInstance(BinaryPreferencesBuilder.java:251)  at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:226)  at com.basip.intercom.binary.BinaryPreferenceHelper.getPreferencesInstance(BinaryPreferenceHelper.java:25)  at com.dnake.talk.TalkApp.onCreate(TalkApp.java:20)  at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007)  at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344)  at android.app.ActivityThread.access$1500(ActivityThread.java:135)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:136)  at android.app.ActivityThread.main(ActivityThread.java:5017)  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:779)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)  at dalvik.system.NativeStart.main(Native Method)  Caused by: com.ironz.binaryprefs.exception.FileOperationException: java.io.FileNotFoundException: /dnake/cfg/preferences/intercom_options/values/pref_monitor_mode: open failed: EACCES (Permission denied) at com.ironz.binaryprefs.file.adapter.NioFileAdapter.fetchInternal(NioFileAdapter.java:77) at com.ironz.binaryprefs.file.adapter.NioFileAdapter.fetchBackupOrOriginal(NioFileAdapter.java:62) at com.ironz.binaryprefs.file.adapter.NioFileAdapter.fetch(NioFileAdapter.java:52) at com.ironz.binaryprefs.file.transaction.MultiProcessTransactionImpl.fetchInternal(MultiProcessTransactionImpl.java:55) at com.ironz.binaryprefs.file.transaction.MultiProcessTransactionImpl.fetch(MultiProcessTransactionImpl.java:34) at com.ironz.binaryprefs.BinaryPreferences.fetchInternal(BinaryPreferences.java:62) at com.ironz.binaryprefs.BinaryPreferences.access$000(BinaryPreferences.java:17) at com.ironz.binaryprefs.BinaryPreferences$1.run(BinaryPreferences.java:49) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:841) Caused by: java.io.FileNotFoundException: /dnake/cfg/preferences/intercom_opt

Clear all prefs at once

In my app, user can log out so i must clear all saved info.

I have class AppCleaner that listens to user events and do clean

object AppCleaner: KoinComponent {

    private lateinit var applicationContext: Context

    private val roomDatabase by inject<Database>()
    private val userLifecycle by inject<Lifecycle>(userLifecycleQualifier)

    fun init(context: Context) {
        applicationContext = context.applicationContext

        GlobalScope.launch {
            userLifecycle.stopped()
                .collect {
                    clearCache()
                    clearRoom()
                    clearSharedPrefs()
                }
        }
    }

    private fun clearRoom() { roomDatabase.clearAllTables() }

    private fun clearSharedPrefs() {
        applicationContext.filesDir.parentFile?.let { root ->
            File(root, "shared_prefs")
                .list()
                ?.let { for (fileName in it) {
                    applicationContext.getSharedPreferences(
                        fileName.replace(".xml", ""),
                        Service.MODE_PRIVATE
                    ).edit { clear() }
                } }
        }
    }

    private fun clearBinaryPrefs() {
        TODO()
    }

    private fun clearCache() { applicationContext.cacheDir.deleteRecursively() }

}

Can you help me with solution that will clean all binary prefs?

Crash by fetching a preference

I found the following crash in the Crashlytics. Can't reproduce on my test devices. I use 0.9.9 version. Can update to 1.0.0-BETA-2 possibly solve it?

Do you have any ideas why it may happen?

Fatal Exception: java.lang.RuntimeException: Unable to create application: com.ironz.binaryprefs.exception.FileOperationException: java.util.concurrent.ExecutionException: com.ironz.binaryprefs.exception.LockOperationException: java.io.FileNotFoundException: /data/data/example.android.com/cache/preferences/debug_pref/lock/debug_pref.lock: open failed: ENOENT (No such file or directory)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4881)
at android.app.ActivityThread.access$1400(ActivityThread.java:181)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1537)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5660)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:963)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:758)
Caused by com.ironz.binaryprefs.exception.FileOperationException: java.util.concurrent.ExecutionException: com.ironz.binaryprefs.exception.LockOperationException: java.io.FileNotFoundException: /data/data/example.android.com/cache/preferences/debug_pref/lock/debug_pref.lock: open failed: ENOENT (No such file or directory)
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:44)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64)
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java)
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88)
****************************
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1017)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4872)
at android.app.ActivityThread.access$1400(ActivityThread.java:181)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1537)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5660)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:963)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:758)
Caused by java.util.concurrent.ExecutionException: com.ironz.binaryprefs.exception.LockOperationException: java.io.FileNotFoundException: /data/data/example.android.com/cache/preferences/debug_pref/lock/debug_pref.lock: open failed: ENOENT (No such file or directory)
at java.util.concurrent.FutureTask.report(FutureTask.java:93)
at java.util.concurrent.FutureTask.get(FutureTask.java:163)
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:42)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64)
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java)
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88)
****************************
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1017)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4872)
at android.app.ActivityThread.access$1400(ActivityThread.java:181)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1537)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5660)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:963)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:758)
Caused by com.ironz.binaryprefs.exception.LockOperationException: java.io.FileNotFoundException: /data/data/example.android.com/cache/preferences/debug_pref/lock/debug_pref.lock: open failed: ENOENT (No such file or directory)
at com.ironz.binaryprefs.lock.ProcessFileLock.lock(ProcessFileLock.java:43)
at com.ironz.binaryprefs.file.transaction.MultiProcessTransactionImpl.fetch(MultiProcessTransactionImpl.java:24)
at com.ironz.binaryprefs.BinaryPreferences$1.run(BinaryPreferences.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by java.io.FileNotFoundException: /data/data/example.android.com/cache/preferences/debug_pref/lock/debug_pref.lock: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:496)
at java.io.RandomAccessFile.(RandomAccessFile.java)
at com.ironz.binaryprefs.lock.ProcessFileLock.lock(ProcessFileLock.java:30)
at com.ironz.binaryprefs.file.transaction.MultiProcessTransactionImpl.fetch(MultiProcessTransactionImpl.java:24)
at com.ironz.binaryprefs.BinaryPreferences$1.run(BinaryPreferences.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by android.system.ErrnoException: open failed: ENOENT (No such file or directory)
at libcore.io.Posix.open(Posix.java)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
at libcore.io.IoBridge.open(IoBridge.java:482)
at java.io.RandomAccessFile.(RandomAccessFile.java)
at com.ironz.binaryprefs.lock.ProcessFileLock.lock(ProcessFileLock.java:30)
at com.ironz.binaryprefs.file.transaction.MultiProcessTransactionImpl.fetch(MultiProcessTransactionImpl.java:24)
at com.ironz.binaryprefs.BinaryPreferences$1.run(BinaryPreferences.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)

Add lazy evaluation for default values

In most cases we do not need to have instance of default value because value already stored for the key.

For optimisation purposes will be great to extend interface by adding lazy evaluation of default value. And evaluate it only in case if key is not presented in storage.

exception appears during reinitializing Preferences

in build.gradle:
implementation 'com.github.iamironz:binaryprefs:0.9.9'

сreate the settings as follows

return new BinaryPreferencesBuilder(MainApplication.getInstance())
            .name(BuildConfig.PREFERENCE_FOLDER)
            .encryption(customEncryptor)
            .registerPersistable(MyEntity.KEY, MyEntity.class)
            .build();//crash is here

entity class

public final class MyEntity implements Persistable, Parcelable {

   private int mId;
   private String mSource;
   private long mLastModification;
   private int mRating;


   public MyEntity(int id, String source, long lastModification, int rating) {
      mId = id;
      mSource = source;
      mLastModification = lastModification;
      mRating = rating;
   }

   //...

   @Override
   public void writeExternal(DataOutput out) {
      out.writeInt(mId);
      out.writeString(mSource);
      out.writeLong(mLastModification);
      out.writeInt(mRating);
   }

   @Override
   public void readExternal(DataInput in) {
      mId = in.readInt();
      mSource = in.readString();
      mLastModification = in.readLong();
      mRating = in.readInt();
   }

   @Override
   public Persistable deepClone() {
      return new MyEntity(mId, mSource, mLastModification, mRating);
   }

   //...
}

When first created Preference it's all right. But if called

mPreferences.edit().putPersistable(key, myEntityInstance).commit();

and then app is killed and removed from recents screen then during the next initialization appears exception:

com.ironz.binaryprefs.exception.FileOperationException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:44)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64)
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java:43)
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88)
at by.klepcha.app.dagger.ActivityModule.providePreferences(ActivityModule.java:53)
...
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
Caused by: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at java.util.concurrent.FutureTask.report(FutureTask.java:93)
at java.util.concurrent.FutureTask.get(FutureTask.java:163)
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:42)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64) 
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java:43) 
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88) 
at by.klepcha.app.dagger.ActivityModule.providePreferences(ActivityModule.java:53) 
...
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703) 
Caused by: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at com.ironz.binaryprefs.serialization.SerializerFactory.deserialize(SerializerFactory.java:54)
at com.ironz.binaryprefs.BinaryPreferences$1.run(BinaryPreferences.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)

Problem with getting data from Set<String>

I'm trying to save bundle to binaryPrefs for that I'm recursively saving <key, value> to Set<String> and adding separator to key for saving deep of bundle data. But when i try to get data from this set sometimes i catch next error:

key's value is zero bytes for deserialize at com.ironz.binaryprefs.task.FutureBarrier.completeBlockingWithResultUnsafe(FutureBarrier.java)
at com.ironz.binaryprefs.init.LazyFetchStrategy.fetchCacheCandidates(LazyFetchStrategy.java)
getInternal(LazyFetchStrategy.java)
at com.ironz.binaryprefs.init.LazyFetchStrategy.getValue(LazyFetchStrategy.java)
getAll(LazyFetchStrategy.java)
contains(LazyFetchStrategy.java)
access$000(LazyFetchStrategy.java)
at com.ironz.binaryprefs.BinaryPreferences.getAll(BinaryPreferences.java)

Stetho support

Hi. It will be cool to support Stetho. I think it more convenient then logs because you can see prefs and database in the same place.

Encryption key update

Hello! Thanks for this library.
What is the best way to update encryptionkey for keyEncryption and valueEncryption?

How to make changes in Persistable class

Hello! Thanks for this library.

I created singleton instance:

BinaryPreferencesBuilder(context)
.keyEncryption(XorKeyEncryptionImpl(mySecretKey))  
.valueEncryption(AesValueEncryptionImpl(mySecretKey, MyInitialVector))  
.registerPersistable(MyClass.KEY, MyClass::class.java)  
.build()

And it is working as i expected.
After some time i had to add some additional fields to my persistable, and i got UnsupportedClassVersionError
Cannot find Persistable type for .����G� key

I read migration section at the wiki but have no idea how to correctrly implement that and not sure that is related with my issue.

There is my Persistable class.

class MyClass: Persistable {
    companion object {
        val KEY = "MyClass"
    }

    override fun readExternal(input: DataInput) {
        login = input.readString()
        password = input.readString()
        expiration = input.readLong()
        saveTime = input.readLong()
        saveLocalTime = input.readLong()
    }

    override fun deepClone(): Persistable {
        val value = LogoPass()
        value.login = login
        value.password = password
        value.expiration = expiration
        value.saveTime = saveTime
        value.saveLocalTime = saveLocalTime
        return value
    }

    override fun writeExternal(out: DataOutput) {
        out.writeString(login)
        out.writeString(password)
        out.writeLong(expiration)
        out.writeLong(saveTime)
        out.writeLong(saveLocalTime)
    }

    var login: String = ""
    var password: String = ""
    var expiration: Long = 0
    var saveTime: Long = 0
    var saveLocalTime: Long = 0
}

saveLocalTime - new field

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.