a SharedPreferences replacement for Android with multiprocess support

Overview

DEPRECATED - no longer actively maintained

Tray - a SharedPreferences replacement for Android

Build Status License

If you have read the documentation of the SharedPreferences you might have seen one of these warnings:

Note: This class does not support use across multiple processes.

Google even deprecated the multiprocess support because it never worked relieable

Tray is this mentioned explicit cross-process data management approach powered by a ContentProvider. Tray also provides an advanced API which makes it super easy to access and maintain your data with upgrade and migrate mechanisms. Welcome to SharedPreferences 2.0 aka Tray.

Features

Usage

Simple tutorial how to use Tray in your project instead of the SharedPreferences

Save and read preferences

// create a preference accessor. This is for global app preferences.
final AppPreferences appPreferences = new AppPreferences(getContext()); // this Preference comes for free from the library
// save a key value pair
appPreferences.put("key", "lorem ipsum");

// read the value for your key. the second parameter is a fallback (optional otherwise throws)
final String value = appPreferences.getString("key", "default");
Log.v(TAG, "value: " + value); // value: lorem ipsum

// read a key that isn't saved. returns the default (or throws without default)
final String defaultValue = appPreferences.getString("key2", "default");
Log.v(TAG, "value: " + defaultValue); // value: default

No Editor, no commit() or apply() 😉

Create your own preference module

It's recommended to bundle preferences in groups, so called modules instead of putting everything in one global module. If you were using SharedPreferences before, you might have used different files to group your preferences. Extending the TrayModulePreferences and put all Keys inside this class is a recommended way to keep your code clean.

// create a preference accessor for a module
public class MyModulePreference extends TrayPreferences {

    public static String KEY_IS_FIRST_LAUNCH = "first_launch";

    public MyModulePreference(final Context context) {
        super(context, "myModule", 1);
    }
}
// accessing the preferences for my own module
final MyModulePreference myModulePreference = new MyModulePreference(getContext());
myModulePreference.put(MyModulePreference.KEY_IS_FIRST_LAUNCH, false);

See the sample project for more

Like the Android SQLiteOpenHelper a TrayPreference lets you implement methods to handle versioning.

public class MyModulePreference extends TrayPreferences {

    public MyModulePreference(final Context context) {
        super(context, "myModule", 1);
    }

    @Override
    protected void onCreate(final int initialVersion) {
        super.onCreate(initialVersion);
    }

    @Override
    protected void onUpgrade(final int oldVersion, final int newVersion) {
        super.onUpgrade(oldVersion, newVersion);
    }

    @Override
    protected void onDowngrade(final int oldVersion, final int newVersion) {
        super.onDowngrade(oldVersion, newVersion);
    }
}

// TOOD add clear sample

Migrate from SharedPreferences to Tray

To migrate values from SharedPreferences you have to create you own preference module. This module will be now store all of your SharedPreferences values.

public class ImportPreferences extends TrayPreferences {

    // The SharedPreferences name
    private static final String SHARED_PREFERENCES_FILE_NAME = "PREF_NAME";
    
    // The key inside the SHARED_PREFERENCES_NAME
    private static final String KEY_FIRST_LAUNCH = "KEY_FIRST_LAUNCH";
    
    // The new key for this module
    private static final String KEY_FIRST_LAUNCH_TRAY = "KEY_FIRST_LAUNCH_TRAY";
    
    public ImportPreferences(@NonNull Context context) {
        super(context, "myImportModule", 1);
    }    
    
    // Called only once when the module was created
    @Override
    protected void onCreate(int initialVersion) {
        super.onCreate(initialVersion);
            
        // Create a SharedPreferencesImport object
        SharedPreferencesImport importPref = 
            new SharedPreferencesImport(getContext(), 
                SHARED_PREFERENCES_FILE_NAME, KEY_FIRST_LAUNCH, KEY_FIRST_LAUNCH_TRAY);
            
        // Finally migrate it
        migrate(importPref);
    }
}

Getting Started

Add Tray to your project
GitHub Packages
repositories {
    maven {
        url = uri("https://maven.pkg.github.com/GCX-HCI/tray")
    }
}

dependencies {
    implementation "net.grandcentrix.tray:tray:0.12.0"
}
JCenter (deprecated)
repositories {
    jcenter()
}

dependencies {
    implementation "net.grandcentrix.tray:tray:0.12.0"
}

More on the ContentProvider configuration can be found in the wiki

Testcoverage 100%

Tray has 100% test coverage and we'll try to keep it at that level for stable releases.

You can run the coverage report with ./gradlew createDebugCoverageReport. You'll find the output in library/build/outputs/coverage/debug/index.html which looks like this:

coverage report

You can check the coverage report at codecov.io

Those ~170 tests will help us indicate bugs in the future before we publish them. Don't think the code is 100% bug free based on the test coverage.

Build state

Build Status

codecov.io

ContentProvider is overkill

At first, it was the simplest way to use IPC with Binder to solve the multiprocess problem. Using the ContentProvider with a database turned out to be very handy when it comes to save metadata. We thought about replacing the database with the real SharedPreferences to boost the performance (the SharedPreferences do not access the disk for every read/write action which causes the multiprocess problem btw) but the metadata seemed to be more valuable to us. see more informations

If you have found a better solution implement the TrayStorage and contribute to this project! We would appreciate it.

That said, yes the performance isn't as good as the SharedPreferences. But the performance is good enough to save/access single key value pairs synchron. If you want to save more you should think about a simple database.

Missing Features

Tray is ready to use without showblockers! But here are some nice to have features for the future:

  • Reactive wrapper to observe values
  • no support to save Set<String>. Is someone using this?
  • more metadata fields: (i.e. app version code/name)

Roadmap

  • performance tests
  • memory cache for based on contentobservers
  • prevent app crashes due to database errors
  • rx wrapper for changes
  • save additional data types (Set<String>, byte[])

Versions

Version 0.11.1 07.02.17
  • preference key cannot be empty #84
  • clearBut(TrayPreference) -> clearBut(AbstractTrayPreference) #89
Version 0.11.0 07.09.16
  • all accessor methods return boolean indicating the success of i.e. put, remove. They will never again throw an error. #69
  • new contains() method #74
Version 0.10.0 31.05.16
  • All features and changes of the 1.0.0-rc preview builds
  • #65 Fix deletion of non string migrated shared preferences.
Version 1.0.0 preview - postponed until the memory cache is ready
1.0.0-rc3 05.11.15
  • hotfix for listener on Android 6.0 which has caused a infinity loop #55
  • the sample project includes now a way to test the multi process support compared to the SharedPreferences
  • removed unnecessary write operation for every version check #54
1.0.0-rc2 24.09.15
  • added logging for all data changing methods. Enable via adb shell setprop log.tag.Tray VERBOSE
1.0.0-rc1 21.09.15
  • Android M Auto Backup feature support (see the Documentation)
    • split up database for user and device specific data (device specific data can now be excluded from the auto backup)
    • TrayPreferences has now an optional 3. constructor parameter TrayStorage.Type, USER or DEVICE indicating the internal database (required for Android M Auto Backup). Default is USER
  • New methods and changes
    • PreferenceAccessor#wipe() clears the preference data and it's internal data (version)
    • TrayPreferences#annexModule(String name) imports a module by name and wipes it afterwards. This allows renaming of preferences without losing data
    • AbstractTrayPreference#annex(ModularizedStorage<TrayItem>) allows a storage to import another storage, wipes the imported afterwards
    • Preference #onCreate(...) and #onUpgrade(...) aren't abstract anymore because they don't require an implementation
  • Deprecations (will be removed soon)
    • TrayAppPreferences is now deprecated. Use AppPreferences instead (renaming)
    • TrayModulePreferences is now deprecated. Use TrayPreferences instead to extend from for your own Preferences
  • Internal structure
    • new package structure. merged packages accessor, migration and storage into core
    • package provider contains a TrayStorage implementation with a ContentProvider. Is easy exchangeable with another TrayStorage implementation
    • ModularizedTrayPreference is now called AbstractTrayPreference
    • ModularizedStorage was renamed to TrayStorage
Version 0.9.2 02.06.15
  • getContext() is working in TrayModulePreference#onCreate
Version 0.9.1 18.05.15
  • saving null with mPref.put(KEY, null) works now
  • access to preference with throwing methods instead of default value (throws ItemNotFoundException). Example: mPref.getString(KEY); instead of mPref.getString(KEY, "defaultValue");
  • WrongTypeException when accessing a preference with a different type and the data isn't parsable. Float (10.1f) -> String works, String ("10.1") -> Float works, String ("test") -> Float throws!
  • javadoc in now included in aar
Version 0.9 27.04.15
  • initial public release
Version 0.2 - 0.8
  • Refactoring
  • 100% Testing
  • Bugfixing
Version 0.1 17.09.14
  • first working prototype

Contributors

License

Copyright 2015 grandcentrix GmbH

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.
Comments
  • Can't initialise new AppPreferences(getContext())

    Can't initialise new AppPreferences(getContext())

    Hi everyone, here asking for some help!

    It crashed in the TrayContract.java

    I get a nullpointerexpection, in this method @NonNull private static String getAuthority(@NonNull final Context context) { return TextUtils.isEmpty(sTestAuthority) ? context.getString(R.string.tray__authority) : sTestAuthority; }

    I believe it can't get the context.getString(R.string.tray__authority) in here.

    • I set the the tray__authority and I cleaned the project.
    • I set one different value for every flavour, based on the the ApplicationId.
    • if I do context.getString(R.string.tray__authority) I get the right value.
    • It's the same context has the one I gave to your AppPreferences.

    I don't understand the issue, can somebody help?

    opened by dfloureiro 11
  •  java.lang.IllegalStateException

    java.lang.IllegalStateException

    java.lang.IllegalStateException: could not access stored data with uri content://com.taobao.qianniu.tray/internal_preferences/qianniu/version. Is the provider registered in the manifest of your application? at net.grandcentrix.tray.provider.TrayProviderHelper.queryProvider(SourceFile:196) at net.grandcentrix.tray.storage.TrayStorage.getVersion(SourceFile:85) at net.grandcentrix.tray.accessor.Preference.changeVersion(SourceFile:158) at net.grandcentrix.tray.accessor.Preference.(SourceFile:52) at net.grandcentrix.tray.accessor.TrayPreference.(SourceFile:33) at net.grandcentrix.tray.TrayModulePreferences.(SourceFile:40)

    MediaPad X1 7.0 11 PE-TL00M 7 Coolpad 9150W 6 HUAWEI P7-L07 6 PE-TL20 6 Che2-UL00 6 G621-TL00 5 vivo X5Pro D 5 Coolpad 8675-A 4 SM-N900

    bug 
    opened by HandsomeL 11
  • Set unique authority prefix automatically

    Set unique authority prefix automatically

    If developer include tray library in their own library, it's difficult to get app applicationId in library build.gradle. For users who use that library may don't have to realize what tray__authority is.

    opened by b95505017 10
  • Compiler complains passing TrayStorage.Type.USER

    Compiler complains passing TrayStorage.Type.USER

    The following causes the compiler to complain; TrayStorage.Type.USER needs to be an int.

    private class MyPreference extends TrayPreferences {
        public MyPreference(@NonNull final Context context) {
            super(context, "myModule", VERSION, TrayStorage.Type.USER);
        }
    }
    
    opened by jonameson 5
  • NullPointerException at unregisterOnTrayPreferenceChangeListener in Service

    NullPointerException at unregisterOnTrayPreferenceChangeListener in Service

    tray Version 0.12.0

    tray is initialized in onStartCommand of a service

    Device(s) (issues reported in Play store on Samsung Galaxy S8, A8 and S8+, but in pre launch test on multiple other devices as well )

    minSdkVersion 21, compile and targetSDK 29

    Stacktrace

    java.lang.RuntimeException: at android.app.ActivityThread.handleStopService (ActivityThread.java:3948) at android.app.ActivityThread.access$1800 (ActivityThread.java:237) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1828) at android.os.Handler.dispatchMessage (Handler.java:106) at android.os.Looper.loop (Looper.java:214) at android.app.ActivityThread.main (ActivityThread.java:7078) at java.lang.reflect.Method.invoke (Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:494) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:964) Caused by: java.lang.NullPointerException: at com.android.internal.util.Preconditions.checkNotNull (Preconditions.java:128) at android.content.ContentResolver.unregisterContentObserver (ContentResolver.java:1993) at net.grandcentrix.tray.provider.ContentProviderStorage.unregisterOnTrayPreferenceChangeListener (ContentProviderStorage.java:362) at net.grandcentrix.tray.core.AbstractTrayPreference.unregisterOnTrayPreferenceChangeListener (AbstractTrayPreference.java:173) at com.twom.bico.services.JepsterService.destroyService (JepsterService.java:583) at com.twom.bico.services.JepsterService.onDestroy (JepsterService.java:345) at android.app.ActivityThread.handleStopService (ActivityThread.java:3928) ```

    For some reason nullpointer exceptions are reported when the code wants to unregister the listener. In the code this is called just before stopping the Service. Code:

    ...

        if (mMultiProcessPreferences != null && mAppPrefsListener != null){
            mMultiProcessPreferences.unregisterOnTrayPreferenceChangeListener(mAppPrefsListener);
        }
    
        // Stop running service in foreground.
        this.stopForeground(true);
    
        // Cancel the persistent notification.
        mNotificationManager.cancel(NOTIFICATION_ID);
    
        //Stop service
        stopSelf();
    

    }

    Do you have any explanation or hint why this happens? I can't reproduce it in Android Studio, but i have got multiple reports in the Play Store and also in the automatic pre-launch tests.

    Thanks a lot in advance!

    opened by tomwassink 4
  • has lot of blocked operations reported from blockcanary

    has lot of blocked operations reported from blockcanary

    I saw lot of blocked reported from blockcanary when i cannot any type prefs read (getInt getBoolean), i have around 100 try items saved in TrayPreferences table. it should be very faster to read

    opened by eggcaker 4
  • "could not access stored data with uri content" error

    My application is the only launcher of the android firmware.I got the follow error: The TrayPreferences is initialized in MyApplication.onCreate

    08-12 14:52:14.283 E/ActivityThread( 1462): Failed to find provider info for com.testtay.user_preference
    08-12 14:52:14.293 E/CrashHandler( 1462): encountered a fatal error
    08-12 14:52:14.293 E/CrashHandler( 1462): java.lang.RuntimeException: Unable to create application com.testtay.application.MyApplication: java.lang.IllegalStateException: could not access stored data with uri content://com.testtay.user_preference/internal_preferences/group/version?backup=true. Is the provider registered in the manifest of your application?
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4347)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.app.ActivityThread.access$1500(ActivityThread.java:135)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.os.Handler.dispatchMessage(Handler.java:102)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.os.Looper.loop(Looper.java:136)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.app.ActivityThread.main(ActivityThread.java:5017)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at java.lang.reflect.Method.invokeNative(Native Method)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at java.lang.reflect.Method.invoke(Method.java:515)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:788)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:604)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at dalvik.system.NativeStart.main(Native Method)
    08-12 14:52:14.293 E/CrashHandler( 1462): Caused by: java.lang.IllegalStateException: could not access stored data with uri content://com.testtay.user_preference/internal_preferences/group/version?backup=true. Is the provider registered in the manifest of your application?
    08-12 14:52:14.293 E/CrashHandler( 1462):       at net.grandcentrix.tray.provider.TrayProviderHelper.queryProvider(TrayProviderHelper.java:145)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at net.grandcentrix.tray.provider.ContentProviderStorage.getVersion(ContentProviderStorage.java:214)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at net.grandcentrix.tray.core.Preferences.changeVersion(Preferences.java:224)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at net.grandcentrix.tray.core.Preferences.<init>(Preferences.java:51)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at net.grandcentrix.tray.core.AbstractTrayPreference.<init>(AbstractTrayPreference.java:31)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:43)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:48)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.testtay.common.preferences.CacheTrayPreferences.<init>(CacheTrayPreferences.java:24)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.testtay.common.preferences.UserPreferences.<init>(UserPreferences.java:34)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.testtay.common.preferences.UserPreferences.init(UserPreferences.java:21)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.testtay.utils.ProcessUtils.initCommon(ProcessUtils.java:149)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.testtay.application.process.MainProcessApp.create(MainProcessApp.java:64)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at com.testtay.application.MyApplication.onCreate(MyApplication.java:50)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1021)
    08-12 14:52:14.293 E/CrashHandler( 1462):       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344)
    08-12 14:52:14.293 E/CrashHandler( 1462):       ... 10 more
    
    opened by ElegantWang 4
  • TrayContentProvider does not found when using Gradle 1.5.0-beta2 & proguard enabled

    TrayContentProvider does not found when using Gradle 1.5.0-beta2 & proguard enabled

    Though I've just reported the issue in Google's issue tracker, I thought it would be good to also report here.

    I just got following error when tried to use Android Gradle plugin 1.5.0-beta2 with proguard enabled. without proguard, it works fine. but when I enable proguard, it starts crashing right after I launch the app. With Gradle plugin 1.3.0, it works fine.

    I'm using 1.0.0-rc3 of the tray.

    java.lang.RuntimeException: Unable to get provider net.grandcentrix.tray.provider.TrayContentProvider: java.lang.ClassNotFoundException: Didn't find class "net.grandcentrix.tray.provider.TrayContentProvider" on path: DexPathList[[zip file "/data/app/net.yslibrary.omnitweety-1/base.apk"],nativeLibraryDirectories=[/data/app/net.yslibrary.omnitweety-1/lib/arm64, /data/app/net.yslibrary.omnitweety-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]
                                                         at android.app.ActivityThread.installProvider(ActivityThread.java:5156)
                                                         at android.app.ActivityThread.installContentProviders(ActivityThread.java:4748)
                                                         at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4688)
                                                         at android.app.ActivityThread.-wrap1(ActivityThread.java)
                                                         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
                                                         at android.os.Handler.dispatchMessage(Handler.java:102)
                                                         at android.os.Looper.loop(Looper.java:148)
                                                         at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                         at java.lang.reflect.Method.invoke(Native Method)
                                                         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                      Caused by: java.lang.ClassNotFoundException: Didn't find class "net.grandcentrix.tray.provider.TrayContentProvider" on path: DexPathList[[zip file "/data/app/net.yslibrary.omnitweety-1/base.apk"],nativeLibraryDirectories=[/data/app/net.yslibrary.omnitweety-1/lib/arm64, /data/app/net.yslibrary.omnitweety-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]
                                                         at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
                                                         at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
                                                         at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
                                                         at android.app.ActivityThread.installProvider(ActivityThread.java:5141)
                                                         at android.app.ActivityThread.installContentProviders(ActivityThread.java:4748) 
                                                         at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4688) 
                                                         at android.app.ActivityThread.-wrap1(ActivityThread.java) 
                                                         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405) 
                                                         at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                         at android.os.Looper.loop(Looper.java:148) 
                                                         at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                         at java.lang.reflect.Method.invoke(Native Method) 
                                                         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
                                                        Suppressed: java.lang.ClassNotFoundException: net.grandcentrix.tray.provider.TrayContentProvider
                                                         at java.lang.Class.classForName(Native Method)
                                                         at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
                                                         at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
                                                         at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                                                                ... 12 more
                                                      Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
    
    opened by yshrsmz 4
  • Failed to open database '/data/user/0/com.xxx.xxx/databases/tray.db'

    Failed to open database '/data/user/0/com.xxx.xxx/databases/tray.db'

    tray Version (E.g. 0.12.0)

    0.11.1

    How have you setup tray (E.g. Initialized in Application.onCreate, in an Activity, BroadcastReceiver, IntentService, MainThread)

    compile 'net.grandcentrix.tray:tray:0.11.1'

    Device(s) (E.g. Samsung Galaxy S8)

    360Phone

    Android Version (E.g. Marshmallow or better API 23)

    Android7.1.1

    Stacktrace

    Stacktrace
    10-28 11:54:03.324 20407 20407 W ContextImpl: Failed to ensure /data/user/0/com.xxx.xxx/databases: mkdir failed: EACCES (Permission denied)
    10-28 11:54:03.324 20407 20407 E SQLiteLog: (14) cannot open file at line 32456 of [bda77dda96]
    10-28 11:54:03.324 20407 20407 E SQLiteLog: (14) os_unix.c:32456: (13) open(/data/user/0/com.xxx.xxx/databases/tray.db) - 
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: Failed to open database '/data/user/0/com.xxx.xxx/databases/tray.db'.
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:656)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:289)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:187)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.provider.TrayContentProvider.getReadableDatabase(TrayContentProvider.java:117)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.provider.TrayContentProvider.query(TrayContentProvider.java:265)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.content.ContentProvider.query(ContentProvider.java:1045)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.content.ContentProvider$Transport.query(ContentProvider.java:245)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.content.ContentResolver.query(ContentResolver.java:534)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.content.ContentResolver.query(ContentResolver.java:475)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.provider.TrayProviderHelper.queryProvider(TrayProviderHelper.java:169)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.provider.ContentProviderStorage.getVersion(ContentProviderStorage.java:216)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.core.Preferences.changeVersion(Preferences.java:258)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.core.Preferences.isVersionChangeChecked(Preferences.java:292)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.core.Preferences.<init>(Preferences.java:58)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.core.AbstractTrayPreference.<init>(AbstractTrayPreference.java:31)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:43)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:48)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at com.xxx.xxx.module.sp.DebugPreferences.<init>(DebugPreferences.java:15)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at com.xxx.xxx.module.sp.DebugPreferences.getInstance(DebugPreferences.java:24)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at com.xxx.xxx.module.sp.DebugPreferences.doUseHttp(DebugPreferences.java:42)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at com.xxx.xxx.QikuApplication.debugSetting(QikuApplication.java:86)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at com.xxx.xxx.QikuApplication.onCreate(QikuApplication.java:44)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1025)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5509)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.app.ActivityThread.-wrap2(ActivityThread.java)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1579)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.os.Handler.dispatchMessage(Handler.java:102)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.os.Looper.loop(Looper.java:154)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at android.app.ActivityThread.main(ActivityThread.java:6244)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at java.lang.reflect.Method.invoke(Native Method)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
    10-28 11:54:03.326 20407 20407 E SQLiteDatabase: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:797)
    

    Description (Just a place with additional information, more == better)

    opened by toy-lin 3
  • Performance

    Performance

    Hi,

    I stumble upon another library called DPreference and did a quick test (using latest Tray version). Looks like Tray performance is not that good compare to DPreference, maybe due to DPreference is a simple library. Anyway hopefully will see some improvement for Tray in future.

    OnePlus1
    DPreference called setString 1000 times cost : 403
    DPreference called getString 1000 times cost : 543
    
    Tray called setString 1000 times cost : 8737
    Tray called getString 1000 times cost : 3023
    
    Samsung S8
    DPreference called setString 1000 times cost : 231
    DPreference called getString 1000 times cost : 154
    
    Tray called setString 1000 times cost : 12946
    Tray called getString 1000 times cost : 7965
    
    opened by xDragonZ 3
  • error SQLiteConstraintException on emulator with Android N

    error SQLiteConstraintException on emulator with Android N

    04-28 08:37:18.840 8826-9078/*** E/SQLiteDatabase: Error inserting KEY=version MIGRATED_KEY=null UPDATED=1493368638631 CREATED=1493368638631 MODULE=cookie VALUE=1 android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: TrayInternal.MODULE, TrayInternal.KEY (code 2067) at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782) at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1472) at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1343) at net.grandcentrix.tray.provider.SqliteHelper.insertOrUpdate(SqliteHelper.java:148) at net.grandcentrix.tray.provider.TrayContentProvider.insertOrUpdate(TrayContentProvider.java:206) at net.grandcentrix.tray.provider.TrayContentProvider.insert(TrayContentProvider.java:187) at android.content.ContentProvider$Transport.insert(ContentProvider.java:264) at android.content.ContentResolver.insert(ContentResolver.java:1274) at net.grandcentrix.tray.provider.TrayProviderHelper.persist(TrayProviderHelper.java:151) at net.grandcentrix.tray.provider.TrayProviderHelper.persist(TrayProviderHelper.java:142) at net.grandcentrix.tray.provider.ContentProviderStorage.setVersion(ContentProviderStorage.java:350) at net.grandcentrix.tray.core.Preferences.changeVersion(Preferences.java:272) at net.grandcentrix.tray.core.Preferences.isVersionChangeChecked(Preferences.java:292) at net.grandcentrix.tray.core.Preferences.(Preferences.java:58) at net.grandcentrix.tray.core.AbstractTrayPreference.(AbstractTrayPreference.java:31) at net.grandcentrix.tray.TrayPreferences.(TrayPreferences.java:43) at net.grandcentrix.tray.TrayPreferences.(TrayPreferences.java:48) at ***.module.sp.CookiePreferences.(CookiePreferences.java:23) at ***.util.FileTypeUtil.getCookies(FileTypeUtil.java:839) at ***.util.Util.SendPhoneInfo(Util.java:386) at ***.util.Util.access$000(Util.java:124) at .util.Util$1.run(Util.java:371) 04-28 08:37:18.840 8826-9078/ W/Tray: Couldn't update or insert data. Uri: content://***.tray/internal_preferences/cookie/version?backup=true

    Reference:

    compile 'net.grandcentrix.tray:tray:0.11.1'

    And code at "net.grandcentrix.tray.core.Preferences.changeVersion(Preferences.java:272)" is below:

    getStorage().setVersion(newVersion);

    opened by toy-lin 3
  • ANR that leads to app crashing, support needed

    ANR that leads to app crashing, support needed

    Screenshot_20200927-185251_Play Console

    See attached picture, is self explanatory

    The main issue is when update and migrate your data from one app version to next one with versioned Preferences and a onUpgrade() method - onUpgrade took more than 5 seconds and the foreground service crashes since startForeground() not reached within the 5 seconds.

    opened by Duna 1
  • 不知道怎么回事的bug

    不知道怎么回事的bug

    net.grandcentrix.tray.core.TrayRuntimeException:Internal tray error. Could not find the provider authority. Please fill an issue at https://github.com/grandcentrix/tray/issues

    opened by yangjunjin 1
  • can not support multi app share data

    can not support multi app share data

    I custom authorities in my A app manifest,but the B app can not appoint the authorities to visit the A app data, so why not public the TrayContract.sAuthority set method?

    opened by qiurudong 1
  • java.lang.NoClassDefFoundError: Failed resolution of: Lnet/grandcentrix/tray/R$string;

    java.lang.NoClassDefFoundError: Failed resolution of: Lnet/grandcentrix/tray/R$string;

    tray Version (E.g. 0.12.0)

    How have you setup tray (E.g. Initialized in Application.onCreate, in an Activity, BroadcastReceiver, IntentService, MainThread)

    Application.onCreate

    Device(s) (E.g. Samsung Galaxy S8)

    RedMi

    Android Version (E.g. Marshmallow or better API 23)

    API23

    Stacktrace

    Stacktrace
    03-05 15:55:05.045 15503-15503/com.knew.feed E/AndroidRuntime: FATAL EXCEPTION: main
      Process: com.knew.feed, PID: 15503
      java.lang.NoClassDefFoundError: Failed resolution of: Lnet/grandcentrix/tray/R$string;
          at net.grandcentrix.tray.provider.TrayContract.checkOldWayToSetAuthority(TrayContract.java:92)
          at net.grandcentrix.tray.provider.TrayContract.getAuthority(TrayContract.java:122)
          at net.grandcentrix.tray.provider.TrayContract.generateContentUri(TrayContract.java:109)
          at net.grandcentrix.tray.provider.TrayContract.generateContentUri(TrayContract.java:80)
          at net.grandcentrix.tray.provider.TrayUri.<init>(TrayUri.java:75)
          at net.grandcentrix.tray.provider.ContentProviderStorage.<init>(ContentProviderStorage.java:146)
          at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:43)
          at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:48)
          at com.knew.feed.component.MyAppPreferences.<init>(MyAppPreferences.kt:10)
          at com.knew.feed.App$prefs$2.invoke(App.kt:45)
          at com.knew.feed.App$prefs$2.invoke(App.kt:36)
          at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
          at com.knew.feed.App.getPrefs(App.kt)
          at com.knew.feed.utils.DistributionChannelUtils$prefs$2.invoke(DistributionChannelUtils.kt:17)
          at com.knew.feed.utils.DistributionChannelUtils$prefs$2.invoke(DistributionChannelUtils.kt:14)
          at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
          at com.knew.feed.utils.DistributionChannelUtils.getPrefs(DistributionChannelUtils.kt)
          at com.knew.feed.utils.DistributionChannelUtils.access$getPrefs$p(DistributionChannelUtils.kt:14)
          at com.knew.feed.utils.DistributionChannelUtils$distributionChannel$2.invoke(DistributionChannelUtils.kt:22)
          at com.knew.feed.utils.DistributionChannelUtils$distributionChannel$2.invoke(DistributionChannelUtils.kt:14)
          at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
          at com.knew.feed.utils.DistributionChannelUtils.getDistributionChannel(DistributionChannelUtils.kt)
          at com.knew.feed.utils.DistributionChannelUtils.isDevelopment(DistributionChannelUtils.kt:29)
          at com.knew.feed.utils.LoggerUtilsKt.initLogger(LoggerUtils.kt:35)
          at com.knew.feed.App.init(App.kt:85)
          at com.knew.feed.App.onCreate(App.kt:57)
          at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1018)
          at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5019)
          at android.app.ActivityThread.access$1800(ActivityThread.java:178)
          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578)
          at android.os.Handler.dispatchMessage(Handler.java:111)
          at android.os.Looper.loop(Looper.java:207)
          at android.app.ActivityThread.main(ActivityThread.java:5845)
          at java.lang.reflect.Method.invoke(Native Method)
          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:768)
       Caused by: java.lang.ClassNotFoundException: Didn't find class "net.grandcentrix.tray.R$string" on path: DexPathList[[zip file "/data/app/com.knew.feed-1/base.apk"],nativeLibraryDirectories=[/data/app/com.knew.feed-1/lib/arm, /data/app/com.knew.feed-1/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]
          at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
          at net.grandcentrix.tray.provider.TrayContract.checkOldWayToSetAuthority(TrayContract.java:92) 
          at net.grandcentrix.tray.provider.TrayContract.getAuthority(TrayContract.java:122) 
          at net.grandcentrix.tray.provider.TrayContract.generateContentUri(TrayContract.java:109) 
          at net.grandcentrix.tray.provider.TrayContract.generateContentUri(TrayContract.java:80) 
          at net.grandcentrix.tray.provider.TrayUri.<init>(TrayUri.java:75) 
          at net.grandcentrix.tray.provider.ContentProviderStorage.<init>(ContentProviderStorage.java:146) 
          at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:43) 
          at net.grandcentrix.tray.TrayPreferences.<init>(TrayPreferences.java:48) 
          at com.knew.feed.component.MyAppPreferences.<init>(MyAppPreferences.kt:10) 
          at com.knew.feed.App$prefs$2.invoke(App.kt:45) 
          at com.knew.feed.App$prefs$2.invoke(App.kt:36) 
          at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) 
          at com.knew.feed.App.getPrefs(App.kt) 
          at com.knew.feed.utils.DistributionChannelUtils$prefs$2.invoke(DistributionChannelUtils.kt:17) 
          at com.knew.feed.utils.DistributionChannelUtils$prefs$2.invoke(DistributionChannelUtils.kt:14) 
          at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) 
          at com.knew.feed.utils.DistributionChannelUtils.getPrefs(DistributionChannelUtils.kt) 
          at com.knew.feed.utils.DistributionChannelUtils.access$getPrefs$p(DistributionChannelUtils.kt:14) 
          at com.knew.feed.utils.DistributionChannelUtils$distributionChannel$2.invoke(DistributionChannelUtils.kt:22) 
          at com.knew.feed.utils.DistributionChannelUtils$distributionChannel$2.invoke(DistributionChannelUtils.kt:14) 
          at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) 
          at com.knew.feed.utils.DistributionChannelUtils.getDistributionChannel(DistributionChannelUtils.kt) 
          at com.knew.feed.utils.DistributionChannelUtils.isDevelopment(DistributionChannelUtils.kt:29) 
          at com.knew.feed.utils.LoggerUtilsKt.initLogger(LoggerUtils.kt:35) 
          at com.knew.feed.App.init(App.kt:85) 
          at com.knew.feed.App.onCreate(App.kt:57) 
          at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1018) 
          at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5019) 
          at android.app.ActivityThread.access$1800(ActivityThread.java:178) 
          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578) 
          at android.os.Handler.dispatchMessage(Handler.java:111) 
          at android.os.Looper.loop(Looper.java:207) 
          at android.app.ActivityThread.main(ActivityThread.java:5845) 
          at java.lang.reflect.Method.invoke(Native Method) 
          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907) 
          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:768) 
      	Suppressed: java.lang.ClassNotFoundException: net.grandcentrix.tray.R$string
          at java.lang.Class.classForName(Native Method)
          at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
          at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
          		... 37 more
       Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
    
    

    Description (Just a place with additional information, more == better)

    opened by kennir 1
  • Accessing Outside of Container App 2.0

    Accessing Outside of Container App 2.0

    I understand that you recommend using the ContentProvider API externally to access the main program data. Whether you will access it in a tray compatible way, and whether you can distinguish between internal access and external access by applying package names. The purpose of compatibility is to access the data of the main program when the component application is used as a stand-alone application, so that it can run directly without modifying the code, which will greatly improve the efficiency of component development. Would you consider it?

    opened by cdslily 1
Releases(v0.12.0)
  • v0.12.0(May 5, 2017)

    tray__authority is now deprecated. You'll see a big error in logcat when your are still using it. Instead the <applicationId>.tray will be used as authority.

    If you rely on a specific authority of the ContentProvider (and you really don't) you can change it. Read the wiki for more information.

    dependencies {
        compile 'net.grandcentrix.tray:tray:0.12.0'
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.11.1(Feb 7, 2017)

    • preference key cannot be empty #84, thx @eyedol
    • clearBut(TrayPreference) -> clearBut(AbstractTrayPreference) #89
    dependencies {
        compile 'net.grandcentrix.tray:tray:0.11.1'
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.11.0(Sep 7, 2016)

    Version 0.10.0 07.09.16
    • all accessor methods return boolean indicating the success of i.e. put, remove. They will never again throw an error. #69
    • new contains() method #74
    Source code(tar.gz)
    Source code(zip)
  • v0.10.0(May 31, 2016)

    • All features and changes of the 1.0.0-rc preview builds
    • #65 Fix deletion of non string migrated shared preferences.
    Version 1.0.0 preview - postponed until the memory cache is ready
    1.0.0-rc3 05.11.15
    • hotfix for listener on Android 6.0 which has caused a infinity loop #55
    • the sample project includes now a way to test the multi process support compared to the SharedPreferences
    • removed unnecessary write operation for every version check #54
    1.0.0-rc2 24.09.15
    • added logging for all data changing methods. Enable via adb shell setprop log.tag.Tray VERBOSE
    1.0.0-rc1 21.09.15
    • Android M Auto Backup feature support (see the Documentation)
      • split up database for user and device specific data (device specific data can now be excluded from the auto backup)
      • TrayPreferences has now an optional 3. constructor parameter TrayStorage.Type, USER or DEVICE indicating the internal database (required for Android M Auto Backup). Default is USER
    • New methods and changes
      • PreferenceAccessor#wipe() clears the preference data and it's internal data (version)
      • TrayPreferences#annexModule(String name) imports a module by name and wipes it afterwards. This allows renaming of preferences without losing data
      • AbstractTrayPreference#annex(ModularizedStorage<TrayItem>) allows a storage to import another storage, wipes the imported afterwards
      • Preference #onCreate(...) and #onUpgrade(...) aren't abstract anymore because they don't require an implementation
    • Deprecations (will be removed soon)
      • TrayAppPreferences is now deprecated. Use AppPreferences instead (renaming)
      • TrayModulePreferences is now deprecated. Use TrayPreferences instead to extend from for your own Preferences
    • Internal structure
      • new package structure. merged packages accessor, migration and storage into core
      • package provider contains a TrayStorage implementation with a ContentProvider. Is easy exchangeable with another TrayStorage implementation
      • ModularizedTrayPreference is now called AbstractTrayPreference
      • ModularizedStorage was renamed to TrayStorage
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-rc1(Sep 21, 2015)

    Get it

    compile 'net.grandcentrix.tray:tray:1.0.0-rc1'
    

    Changelog

    • Android M Auto Backup feature support (see the Documentation)
      • split up database for user and device specific data (device specific data can now be excluded from the auto backup)
      • TrayPreferences has now an optional 3. constructor parameter TrayStorage.Type, USER or DEVICE indicating the internal database (required for Android M Auto Backup). Default is USER
    • New methods and changes
      • PreferenceAccessor#wipe() clears the preference data and it's internal data (version)
      • TrayPreferences#annexModule(String name) imports a module by name and wipes it afterwards. This allows renaming of preferences without losing data
      • AbstractTrayPreference#annex(ModularizedStorage<TrayItem>) allows a storage to import another storage, wipes the imported afterwards
      • Preference #onCreate(...) and #onUpgrade(...) aren't abstract anymore because they don't require an implementation
    • Deprecations (will be removed soon)
      • TrayAppPreferences is now deprecated. Use AppPreferences instead (renaming)
      • TrayModulePreferences is now deprecated. Use TrayPreferences instead to extend from for your own Preferences
    • Internal structure
      • new package structure. merged packages accessor, migration and storage into core
      • package provider contains a TrayStorage implementation with a ContentProvider. Is easy exchangeable with another TrayStorage implementation
      • ModularizedTrayPreference is now called AbstractTrayPreference
      • ModularizedStorage was renamed to TrayStorage
    Source code(tar.gz)
    Source code(zip)
  • v0.9.2(Jun 2, 2015)

  • v0.9.1(May 18, 2015)

    • saving null with mPref.put(KEY, null) works now
    • access to preference with throwing methods instead of default value (throws ItemNotFoundException). Example: mPref.getString(KEY); instead of mPref.getString(KEY, "defaultValue");
    • WrongTypeException when accessing a preference with a different type and the data isn't parsable. Float (10.1f) -> String works, String ("10.1") -> Float works, String ("test") -> Float throws!
    • javadoc in now included in aar
    Source code(tar.gz)
    Source code(zip)
  • v0.9(Apr 27, 2015)

Owner
HCI @ gcx
Human-Computer Interaction (HCI) Competence Center @ grandcentrix
HCI @ gcx
Android Secure SharedPreferences Using Facebook Conceal Encryption

SharedChamber Android Project : SharedChamber on top of SharedPreferences using Facebook Conceal Description Conceal provides a set of Java APIs to pe

Hafiq 95 Nov 25, 2022
A lightweight library for config and using SharedPreferences

preferences-helper SharePreferences is very popular with any project and all most all project has SharePreferences for saving data. This library will

Khang Tran 23 May 8, 2021
A support library for VectorDrawable and AnimatedVectorDrawable classes introduced in Lollipop

vector-compat A support library for VectorDrawable and AnimatedVectorDrawable introduced in Lollipop with fully backwards compatible tint support (api

Wael N 1.2k Nov 29, 2022
A library to quickly and easily enable multiple monitoring & support platforms for your mobile apps

You have a small team. Setting up crash reporting tools, event tracking tools, and log management services is not what you want to spend your hours do

Percolate 65 Aug 8, 2022
Long-term support releases of Birday updated with the latest translations

Note: this document is still a work in progress. Birday LTS This repository is based on the 2.1.0 release of https://github.com/m-i-n-a-r/birday. You

Dominik Novosel 1 May 16, 2022
Android Shared preference wrapper than encrypts the values of Shared Preferences. It's not bullet proof security but rather a quick win for incrementally making your android app more secure.

Secure-preferences - Deprecated Please use EncryptedSharedPreferences from androidx.security in preferenced to secure-preference. (There are no active

Scott Alexander-Bown 1.5k Dec 24, 2022
Android library which makes it easy to handle the different obstacles while calling an API (Web Service) in Android App.

API Calling Flow API Calling Flow is a Android library which can help you to simplify handling different conditions while calling an API (Web Service)

Rohit Surwase 19 Nov 9, 2021
Gesture detector framework for multitouch handling on Android, based on Android's ScaleGestureDetector

Android Gesture Detectors Framework Introduction Since I was amazed Android has a ScaleGestureDetector since API level 8 but (still) no such thing as

null 1.1k Nov 30, 2022
Use Android as Rubber Ducky against another Android device

Use Android as Rubber Ducky against another Android device

null 1.4k Jan 9, 2023
Android Utilities Library build in kotlin Provide user 100 of pre defined method to create advanced native android app.

Android Utilities Library build in kotlin Provide user 100 of pre defined method to create advanced native android app.

Shahid Iqbal 4 Nov 29, 2022
A util for setting status bar style on Android App.

StatusBarUtil A util for setting status bar style on Android App. It can work above API 19(KitKat 4.4). 中文版点我 Sample Download StatusBarUtil-Demo Chang

Jaeger 8.8k Jan 6, 2023
A logger with a small, extensible API which provides utility on top of Android's normal Log class.

This is a logger with a small, extensible API which provides utility on top of Android's normal Log class. I copy this class into all the little apps

Jake Wharton 9.8k Dec 30, 2022
Java implementation of a Disk-based LRU cache which specifically targets Android compatibility.

Disk LRU Cache A cache that uses a bounded amount of space on a filesystem. Each cache entry has a string key and a fixed number of values. Each key m

Jake Wharton 5.7k Dec 31, 2022
a simple cache for android and java

ASimpleCache ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架。轻量到只有一个java文件(由十几个类精简而来)。 1、它可以缓存什么东西? 普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 b

Michael Yang 3.7k Dec 14, 2022
gRPC and protocol buffers for Android, Kotlin, and Java.

Wire “A man got to have a code!” - Omar Little See the project website for documentation and APIs. As our teams and programs grow, the variety and vol

Square 3.9k Dec 31, 2022
✔️ Secure, simple key-value storage for Android

Hawk 2.0 Secure, simple key-value storage for android Important Note This version has no backward compatibility with Hawk 1+ versions. If you still wa

Orhan Obut 3.9k Dec 20, 2022
A robust native library loader for Android.

ReLinker A robust native library loader for Android. More information can be found in our blog post Min SDK: 9 JavaDoc Overview The Android PackageMan

Keepsafe 2.9k Dec 27, 2022
A lightning fast, transactional, file-based FIFO for Android and Java.

Tape by Square, Inc. Tape is a collection of queue-related classes for Android and Java. QueueFile is a lightning-fast, transactional, file-based FIFO

Square 2.4k Dec 30, 2022
Joda-Time library with Android specialization

joda-time-android This library is a version of Joda-Time built with Android in mind. Why Joda-Time? Android has built-in date and time handling - why

Daniel Lew 2.6k Dec 9, 2022