PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Android/tray/README.md

https://bitbucket.org/psiphon/psiphon-circumvention-system
Markdown | 280 lines | 193 code | 87 blank | 0 comment | 0 complexity | a08da407bd28795936629f321e427090 MD5 | raw file
Possible License(s): BSD-3-Clause, CC0-1.0, GPL-3.0, Apache-2.0
  1. # Tray - a SharedPreferences replacement for Android
  2. [![Build Status](https://travis-ci.org/grandcentrix/tray.svg?branch=master)](https://travis-ci.org/grandcentrix/tray) [![License](https://img.shields.io/badge/license-Apache%202-green.svg?style=flat)](https://github.com/grandcentrix/tray/blob/master/LICENSE.txt)
  3. If you have read the documentation of the [`SharedPreferences`](http://developer.android.com/reference/android/content/SharedPreferences.html) you might have seen one of these warnings:
  4. >Note: currently this class does not support use across multiple processes. This will be added later.
  5. **Sometimes _later_ becomes _never_!** Google even deprecated the multiprocess support because it never worked relieable
  6. [![](https://cloud.githubusercontent.com/assets/1096485/9793296/110575d2-57e5-11e5-9728-34d3597771b8.png)](http://developer.android.com/reference/android/content/Context.html#MODE_MULTI_PROCESS)
  7. Tray is this mentioned _explicit cross-process data management approach_ powered by a [`ContentProvider`](http://developer.android.com/reference/android/content/ContentProvider.html). 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.
  8. ## Features
  9. - **works multiprocess**
  10. - stores simple data types as key value pairs
  11. - automatically saves metadata for each entry (created, last updated, ...)
  12. - manage your Preferences in modules [TrayPreference](https://github.com/grandcentrix/tray/blob/master/library/src/main/java/net/grandcentrix/tray/TrayPreferences.java)
  13. - Delete single modules, all modules, or [all modules except some very important ones](https://github.com/grandcentrix/tray/blob/master/library/src/main/java/net/grandcentrix/tray/Tray.java#L79)
  14. - update and migrate your data from one app version to next one with versioned Preferences and a [`onUpgrade()`](https://github.com/grandcentrix/tray/blob/14325e182e225e668218fc539f5de0c9b9e524e7/library/src/main/java/net/grandcentrix/tray/core/Preferences.java#L196) method
  15. - Migrate your current data stored in the SharedPreferences to Tray with [`SharedPreferencesImport`](https://github.com/grandcentrix/tray/blob/master/library/src/main/java/net/grandcentrix/tray/core/SharedPreferencesImport.java)
  16. - **tray is 100% unit tested!**
  17. - 0 lint warnings/errors
  18. - ![new_badge](https://cloud.githubusercontent.com/assets/1096485/9856970/37791f1c-5b18-11e5-97e4-53b8984c76e1.gif) Android 6.0 [Auto Backup for Apps](https://developer.android.com/preview/backup/index.html) support! [Read more in the wiki](https://github.com/grandcentrix/tray/wiki/Android-M-Auto-Backup-for-Apps-support)
  19. ## Usage
  20. Simple tutorial how to use Tray in your project instead of the SharedPreferences
  21. ### Save and read preferences
  22. ```java
  23. // create a preference accessor. This is for global app preferences.
  24. final AppPreferences appPreferences = new AppPreferences(getContext()); // this Preference comes for free from the library
  25. // save a key value pair
  26. appPreferences.put("key", "lorem ipsum");
  27. // read the value for your key. the second parameter is a fallback (optional otherwise throws)
  28. final String value = appPreferences.getString("key", "default");
  29. Log.v(TAG, "value: " + value); // value: lorem ipsum
  30. // read a key that isn't saved. returns the default (or throws without default)
  31. final String defaultValue = appPreferences.getString("key2", "default");
  32. Log.v(TAG, "value: " + defaultValue); // value: default
  33. ```
  34. No `Editor`, no `commit()` or `apply()` :wink:
  35. ### Create your own preference module
  36. 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.
  37. ```java
  38. // create a preference accessor for a module
  39. public class MyModulePreference extends TrayPreferences {
  40. public static String KEY_IS_FIRST_LAUNCH = "first_launch";
  41. public MyModulePreference(final Context context) {
  42. super(context, "myModule", 1);
  43. }
  44. }
  45. ```
  46. ```java
  47. // accessing the preferences for my own module
  48. final MyModulePreference myModulePreference = new MyModulePreference(getContext());
  49. myModulePreference.put(MyModulePreference.KEY_IS_FIRST_LAUNCH, false);
  50. ```
  51. See the [sample project](https://github.com/grandcentrix/tray/tree/master/sample) for more
  52. Like the Android [`SQLiteOpenHelper`](http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html) a `TrayPreference` lets you implement methods to handle versioning.
  53. ```java
  54. public class MyModulePreference extends TrayPreferences {
  55. public MyModulePreference(final Context context) {
  56. super(context, "myModule", 1);
  57. }
  58. @Override
  59. protected void onCreate(final int initialVersion) {
  60. super.onCreate(initialVersion);
  61. }
  62. @Override
  63. protected void onUpgrade(final int oldVersion, final int newVersion) {
  64. super.onUpgrade(oldVersion, newVersion);
  65. }
  66. @Override
  67. protected void onDowngrade(final int oldVersion, final int newVersion) {
  68. super.onDowngrade(oldVersion, newVersion);
  69. }
  70. }
  71. ```
  72. `// TOOD add clear sample`
  73. ### Migrate from SharedPreferences to Tray
  74. `// TODO`
  75. ## Getting Started [![Download](https://api.bintray.com/packages/passsy/maven/Tray/images/download.svg) ](https://bintray.com/passsy/maven/Tray/_latestVersion)
  76. ##### Add Tray to your project
  77. Tray is available via [jcenter](http://blog.bintray.com/2015/02/09/android-studio-migration-from-maven-central-to-jcenter/)
  78. ```java
  79. dependencies {
  80. compile 'net.grandcentrix.tray:tray:0.10.0'
  81. }
  82. ```
  83. ##### Set the authority
  84. To set the authority you need to override the string resource of the library with `resValue` in your `build.gradle`
  85. ```java
  86. android {
  87. ...
  88. defaultConfig {
  89. applicationId "your.app.id" // this is your unique applicationId
  90. resValue "string", "tray__authority", "${applicationId}.tray" // add this to set a unique tray authority based on your applicationId
  91. }
  92. }
  93. ```
  94. Clean your project afterwards to generate the `/build/generated/res/generated/BUILDTYPE/values/generated.xml` which should then contain the following value:
  95. ```xml
  96. <!-- Values from default config. -->
  97. <item name="tray__authority" type="string">your.app.id.tray</item>
  98. ```
  99. Tray is based on a ContentProvider. A ContentProvider needs a **unique** authority. When you use the same authority for multiple apps you will be unable to install the app due to a authority conflict with the error message:
  100. ```
  101. Failure [INSTALL_FAILED_CONFLICTING_PROVIDER]
  102. ```
  103. Changing the authority from one version to another app version is no problem! Tray always uses the same database.
  104. If you are using different applicationIds for different buildTypes of flavors read [this](https://blog.grandcentrix.net/how-to-install-different-app-variants-on-one-android-device/) article.
  105. ## Project state
  106. Tray is currently in active development by [grandcentrix](http://www.grandcentrix.net/). We decided to go open source after reaching 100% test coverage.
  107. [grandcentrix](http://www.grandcentrix.net/) uses Tray in production in two apps without problems.
  108. You can follow the development in the [`develop`](https://github.com/grandcentrix/tray/tree/develop) branch.
  109. ## Testcoverage 100%
  110. Tray has 100% test coverage and we'll try to keep it at that level for stable releases.
  111. 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:
  112. ![coverage report](https://cloud.githubusercontent.com/assets/1096485/9990484/fe61888c-6061-11e5-890d-a76f1ef60304.png)
  113. You can check the coverage report at [codecov.io](https://codecov.io/github/grandcentrix/tray?branch=master)
  114. 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.
  115. ## Build state
  116. Branch | Status | Coverage
  117. ------------- | ------------- | -------------
  118. [`master`](https://github.com/grandcentrix/tray/tree/master) | [![Build Status](https://travis-ci.org/grandcentrix/tray.svg?branch=master)](https://travis-ci.org/grandcentrix/tray) | [![codecov.io](http://codecov.io/github/grandcentrix/tray/branch.svg?branch=master)](https://codecov.io/github/grandcentrix/tray?branch=master)
  119. [`develop`](https://github.com/grandcentrix/tray/tree/develop) | [![Build Status](https://travis-ci.org/grandcentrix/tray.svg?branch=develop)](https://travis-ci.org/grandcentrix/tray) | [![codecov.io](http://codecov.io/github/grandcentrix/tray/branch.svg?branch=develop)](https://codecov.io/github/grandcentrix/tray?branch=develop)
  120. ## ContentProvider is overkill
  121. At first, it was the simplest way to use IPC with [`Binder`](http://developer.android.com/reference/android/os/Binder.html) 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](https://github.com/grandcentrix/tray/issues/28#issuecomment-108282253)
  122. If you have found a better solution implement the [`TrayStorage`](https://github.com/grandcentrix/tray/blob/14325e182e225e668218fc539f5de0c9b9e524e7/library/src/main/java/net/grandcentrix/tray/core/TrayStorage.java) and contribute to this project! We would appreciate it.
  123. 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.
  124. ## Missing Features
  125. Tray is ready to use without showblockers! But here are some nice to have features for the future:
  126. - Reactive wrapper to observe values
  127. - no support to save `Set<String>`. Is someone using this?
  128. - more metadata fields: (i.e. app version code/name)
  129. ## Roadmap
  130. - performance tests
  131. - memory cache for based on contentobservers
  132. - prevent app crashes due to database errors
  133. - rx wrapper for changes
  134. - save additional data types (`Set<String>`, `byte[]`)
  135. ## Versions
  136. ##### Version 0.10.0 `31.05.16`
  137. - All features and changes of the 1.0.0-rc preview builds
  138. - #65 Fix deletion of non string migrated shared preferences.
  139. >##### Version 1.0.0 preview - postponed until the memory cache is ready
  140. >###### 1.0.0-rc3 `05.11.15`
  141. - hotfix for listener on Android 6.0 which has caused a infinity loop #55
  142. - the sample project includes now a way to test the multi process support compared to the `SharedPreferences`
  143. - removed unnecessary write operation for every version check #54
  144. >###### 1.0.0-rc2 `24.09.15`
  145. - added logging for all data changing methods. Enable via `adb shell setprop log.tag.Tray VERBOSE`
  146. >###### 1.0.0-rc1 `21.09.15`
  147. - **Android M Auto Backup feature support** (see the [Documentation](https://github.com/grandcentrix/tray/wiki/Android-M-Auto-Backup-for-Apps-support))
  148. - split up database for *user* and *device* specific data (device specific data can now be excluded from the auto backup)
  149. - `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`
  150. - **New methods and changes**
  151. - `PreferenceAccessor#wipe()` clears the preference data and it's internal data (version)
  152. - `TrayPreferences#annexModule(String name)` imports a module by name and wipes it afterwards. This allows renaming of preferences without losing data
  153. - `AbstractTrayPreference#annex(ModularizedStorage<TrayItem>)` allows a storage to import another storage, wipes the imported afterwards
  154. - `Preference` `#onCreate(...)` and `#onUpgrade(...)` aren't abstract anymore because they don't require an implementation
  155. - **Deprecations** (will be removed soon)
  156. - `TrayAppPreferences` is now deprecated. Use `AppPreferences` instead (renaming)
  157. - `TrayModulePreferences` is now deprecated. Use `TrayPreferences` instead to extend from for your own Preferences
  158. - **Internal structure**
  159. - new package structure. merged packages `accessor`, `migration` and `storage` into `core`
  160. - package `provider` contains a `TrayStorage` implementation with a `ContentProvider`. Is easy exchangeable with another `TrayStorage` implementation
  161. - `ModularizedTrayPreference` is now called `AbstractTrayPreference`
  162. - `ModularizedStorage` was renamed to `TrayStorage`
  163. ##### Version 0.9.2 `02.06.15`
  164. - `getContext()` is working in `TrayModulePreference#onCreate`
  165. ##### Version 0.9.1 `18.05.15`
  166. - saving `null` with `mPref.put(KEY, null)` works now
  167. - access to preference with throwing methods instead of default value (throws ItemNotFoundException). Example: `mPref.getString(KEY);` instead of `mPref.getString(KEY, "defaultValue");`
  168. - 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!
  169. - javadoc in now included in aar
  170. ##### Version 0.9 `27.04.15`
  171. - initial public release
  172. ##### Version 0.2 - 0.8
  173. - Refactoring
  174. - 100% Testing
  175. - Bugfixing
  176. ##### Version 0.1 `17.09.14`
  177. - first working prototype
  178. ## Contributors
  179. - Pascal Welsch - https://github.com/passsy
  180. - Jannis Veerkamp - https://github.com/jannisveerkamp
  181. # License
  182. ```
  183. Copyright 2015 grandcentrix GmbH
  184. Licensed under the Apache License, Version 2.0 (the "License");
  185. you may not use this file except in compliance with the License.
  186. You may obtain a copy of the License at
  187. http://www.apache.org/licenses/LICENSE-2.0
  188. Unless required by applicable law or agreed to in writing, software
  189. distributed under the License is distributed on an "AS IS" BASIS,
  190. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  191. See the License for the specific language governing permissions and
  192. limitations under the License.
  193. ```