a SharedPreferences replacement for Android with multiprocess support
a SharedPreferences replacement for Android with multiprocess support
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.
onUpgrade() methodSharedPreferencesImportSimple tutorial how to use Tray in your project instead of the SharedPreferences
…
No Editor, no commit() or apply() :wink:
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
To migrate values from SharedPreferences you have to create you own preference module. This module will be now store all of your SharedPreferences values.
…
repositories {
maven {
url = uri("https://maven.pkg.github.com/GCX-HCI/tray")
}
}
dependencies {
implementation "net.grandcentrix.tray:tray:0.12.0"
}
repositories {
jcenter()
}
dependencies {
implementation "net.grandcentrix.tray:tray:0.12.0"
}
More on the ContentProvider configuration can be found in the wiki
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:
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.
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.
Tray is ready to use without showblockers! But here are some nice to have features for the future:
Set<String>. Is someone using this?Set<String>, byte[])07.02.17clearBut(TrayPreference) -> clearBut(AbstractTrayPreference) #8907.09.16boolean indicating the success of i.e. put, remove. They will never again throw an error. #69contains() method #7431.05.16Version 1.0.0 preview - postponed until the memory cache is ready
1.0.0-rc3
05.11.15
SharedPreferences1.0.0-rc2
24.09.15
adb shell setprop log.tag.Tray VERBOSE1.0.0-rc1
21.09.15
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 USERPreferenceAccessor#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 dataAbstractTrayPreference#annex(ModularizedStorage<TrayItem>) allows a storage to import another storage, wipes the imported afterwardsPreference #onCreate(...) and #onUpgrade(...) aren't abstract anymore because they don't require an implementationTrayAppPreferences is now deprecated. Use AppPreferences instead (renaming)TrayModulePreferences is now deprecated. Use TrayPreferences instead to extend from for your own Preferencesaccessor, migration and storage into coreprovider contains a TrayStorage implementation with a ContentProvider. Is easy exchangeable with another TrayStorage implementationModularizedTrayPreference is now called AbstractTrayPreferenceModularizedStorage was renamed to TrayStorage02.06.15getContext() is working in TrayModulePreference#onCreate18.05.15null with mPref.put(KEY, null) works nowmPref.getString(KEY); instead of mPref.getString(KEY, "defaultValue");10.1f) -> String works, String ("10.1") -> Float works, String ("test") -> Float throws!27.04.1517.09.14Copyright 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.
No open issues yet, or sync has not completed.