# Class SyncedStore

java.lang.Object
com.codename1.continuity.sync.SyncedStore

public final class SyncedStore extends Object

A small key/value store the platform carries between the devices one person signed in to, without them ever being in the same room.

This is the slow, patient half of continuity. `com.codename1.continuity.Continuity` hands the current activity to a device that is here, now; this keeps a handful of durable settings -- which theme, which sort order, which tutorial they already dismissed, the id of the document they are working through -- in step across everything they own.

    SyncedStore.put("sortOrder", "byDate");
    String order = SyncedStore.get("sortOrder", "byName");

##### What it is not

Not storage. Not a database, not a cache, and not a place for anything the app cannot cheerfully do without: the platform decides when to sync, the user can turn the whole mechanism off, and a device that has never been online has an empty store. Treat every read as "the value, or the default" -- which is why there is no read without a default.

Not secret. The contents leave the device and are held by the platform on the user's behalf. Credentials belong in `com.codename1.security.SecureStorage`.

Not large. The platform imposes a total size and a key count, both small; `put` reports a failure to write rather than pretending it stored something.

##### What it costs

Referencing this package is what makes an iOS build ask for the entitlement that gives the app a synced store, which in turn requires the capability to be enabled on the App ID. That is why it is a package of its own: an app that wants continuation to a nearby device and nothing else should not have to arrange an entitlement to get it. Where the platform has no such store -- Android, desktop, the browser -- `isSupported()` is false and every call here is an inert no-op, so the sensible shape is a synced value with a local default behind it.

##### Threading

Called on the event dispatch thread, like the rest of the toolkit. Codename One is single threaded by design -- one thread on each side of a native boundary, marshalled at the boundary rather than locked -- and this class follows that rule rather than making an exception to it.

It is worth stating because the simulation behind `isSupported() == true` on a desktop keeps its key index as a second stored value: two threads writing different NEW keys at once would each read that index, add their own key, and write it back, so one of them would vanish from `keys()` while its value stayed readable by name. The platform stores have no such structure and no such exposure. The answer is the toolkit's answer everywhere else -- call it from the event thread, and use `com.codename1.ui.Display#callSerially(Runnable)` if you are on another one -- not a lock inside a framework that does not have them.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static void`
  `addChangeListener(SyncedStoreListener l)`
  Registers a listener for changes made on the user's other devices.
  `static String`
  `get(String key, String def)`
  Reads a value.
  `static boolean`
  `isSupported()`
  Whether this platform has a store that follows the user between devices.
  `static String[]`
  `keys()`
  Every key currently in the store, in no particular order.
  `static void`
  `notifyChanged()`
  Internal.
  `static boolean`
  `put(String key, String value)`
  Writes a value, replacing any previous value for the key.
  `static void`
  `remove(String key)`
  Deletes a key.
  `static void`
  `removeChangeListener(SyncedStoreListener l)`
  Removes a listener.

  ### Methods inherited from class Object

  `clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Method Details

  - ### isSupported

    public static boolean isSupported()

    Whether this platform has a store that follows the user between devices.

    ###### Returns

    true when the store is available

  - ### put

    public static boolean put(String key, String value)

    Writes a value, replacing any previous value for the key.

    ###### Parameters

    - `key`: the key, must not be null or empty
    - `value`: the value, must not be null; use `remove(String)` to delete

    ###### Returns

    true when the store holds the value afterwards; false when there is no store, or the platform would not take it -- a key count or a size past what it allows

    ###### Not gated on isSupported()

    That was the THIRD layer this was wrong in.

    isSupported() asks whether this build has a store that follows the user between devices, which is the right question for an application deciding whether to offer the feature and the wrong gate for the calls themselves. On iOS the store is a LOCAL persistent one whose cloud propagation is asynchronous, so reads and writes work and reach other devices later.

    The gate was on all three of IOSNative.m, IOSContinuityBridge and here. Removing it from the first two changed nothing, because this one still made every call unreachable -- a fix verified at one layer and dead at the next. Each bridge answers for itself when there is no store: the Android one returns null and no-ops, the iOS one checks its own port flag, and the simulation reads local preferences.

  - ### get

    public static String get(String key, String def)

    Reads a value.

    There is no overload without a default on purpose: the store is genuinely empty on a device that has not synced yet, so every read has to have an answer for that.

    ###### Parameters

    - `key`: the key, must not be null or empty
    - `def`: what to return when the key is absent or the store is unavailable

    ###### Returns

    the value, or `def`

  - ### remove

    public static void remove(String key)

    Deletes a key. Deleting an absent key does nothing.

    ###### Parameters

    - `key`: the key, must not be null or empty

  - ### keys

    public static String[] keys()

    Every key currently in the store, in no particular order.

    ###### Returns

    the keys, never null and empty when the store is unavailable

  - ### addChangeListener

    public static void addChangeListener(SyncedStoreListener l)

    Registers a listener for changes made on the user's other devices.

    ###### Parameters

    - `l`: the listener

  - ### removeChangeListener

    public static void removeChangeListener(SyncedStoreListener l)

    Removes a listener.

    ###### Parameters

    - `l`: the listener

  - ### notifyChanged

    public static void notifyChanged()
    Internal. Invoked by the continuity framework when a port reports that the store changed underneath the app. Application code registers a `SyncedStoreListener` instead.