Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
T

tray

> 编程语言
Open source

a SharedPreferences replacement for Android with multiprocess support

2.3K stars0 likes0 views
WebsiteGitHub

About

a SharedPreferences replacement for Android with multiprocess support

DEPRECATED - no longer actively maintained

Tray - a SharedPreferences replacement for Android

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

  • works multiprocess
  • stores simple data types as key value pairs
  • automatically saves metadata for each entry (created, last updated, ...)
  • manage your Preferences in modules TrayPreference
  • Delete single modules, all modules, or all modules except some very important ones
  • update and migrate your data from one app version to next one with versioned Preferences and a onUpgrade() method
  • Migrate your current data stored in the SharedPreferences to Tray with SharedPreferencesImport
  • tray is 100% unit tested!
  • 0 lint warnings/errors
  • Android 6.0 Auto Backup for Apps support! Read more in the wiki

Usage

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

Save and read preferences

…

No Editor, no commit() or apply() :wink:

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.

…

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:

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

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

  • Pascal Welsch - https://github.com/passsy
  • Jannis Veerkamp - https://github.com/jannisveerkamp

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.

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Javaandroidmultiprocesssharedpreferences

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言