mirror of
https://github.com/google/pebble.git
synced 2025-05-29 14:33:12 +00:00
Import the pebble dev site into devsite/
This commit is contained in:
parent
3b92768480
commit
527858cf4c
1359 changed files with 265431 additions and 0 deletions
240
devsite/source/_guides/events-and-services/persistent-storage.md
Normal file
240
devsite/source/_guides/events-and-services/persistent-storage.md
Normal file
|
@ -0,0 +1,240 @@
|
|||
---
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
title: Persistent Storage
|
||||
description: |
|
||||
Using persistent storage to improve your app's UX.
|
||||
guide_group: events-and-services
|
||||
order: 7
|
||||
related_docs:
|
||||
- Storage
|
||||
---
|
||||
|
||||
Developers can use the ``Storage`` API to persist multiple types of data between
|
||||
app launches, enabling apps to remember information previously entered by the
|
||||
user. A common use-case of this API is to enable the app to remember
|
||||
configuration data chosen in an app's configuration page, removing the
|
||||
tedious need to enter the information on the phone every time the watchapp is
|
||||
launched. Other use cases include to-to lists, stat trackers, game highscores
|
||||
etc.
|
||||
|
||||
Read {% guide_link user-interfaces/app-configuration %} for more information on
|
||||
implementing an app configuration page.
|
||||
|
||||
|
||||
## Persistent Storage Model
|
||||
|
||||
Every app is allocated 4 kB of persistent storage space and can write values to
|
||||
storage using a key, similar to ``AppMessage`` dictionaries or the web
|
||||
`localStorage` API. To recall values, the app simply queries the API using the
|
||||
associated key . Keys are specified in the `uint32_t` type, and each value can
|
||||
have a size up to ``PERSIST_DATA_MAX_LENGTH`` (currently 256 bytes).
|
||||
|
||||
When an app is updated the values saved using the ``Storage`` API will be
|
||||
persisted, but if it is uninstalled they will be removed.
|
||||
|
||||
Apps that make large use of the ``Storage`` API may experience small pauses due
|
||||
to underlying housekeeping operations. Therefore it is recommended to read and
|
||||
write values when an app is launching or exiting, or during a time the user is
|
||||
waiting for some other action to complete.
|
||||
|
||||
|
||||
## Types of Data
|
||||
|
||||
Values can be stored as boolean, integer, string, or arbitrary data structure
|
||||
types. Before retrieving a value, the app should check that it has been
|
||||
previously persisted. If it has not, a default value should be chosen as
|
||||
appropriate.
|
||||
|
||||
```c
|
||||
uint32_t key = 0;
|
||||
int num_items = 0;
|
||||
|
||||
if (persist_exists(key)) {
|
||||
// Read persisted value
|
||||
num_items = persist_read_int(key);
|
||||
} else {
|
||||
// Choose a default value
|
||||
num_items = 10;
|
||||
|
||||
// Remember the default value until the user chooses their own value
|
||||
persist_write_int(key, num_items);
|
||||
}
|
||||
```
|
||||
|
||||
The API provides a 'read' and 'write' function for each of these types,
|
||||
with builtin data types retrieved through assignment, and complex ones into a
|
||||
buffer provided by the app. Examples of each are shown below.
|
||||
|
||||
|
||||
### Booleans
|
||||
|
||||
```c
|
||||
uint32_t key = 0;
|
||||
bool large_font_size = true;
|
||||
```
|
||||
|
||||
```c
|
||||
// Write a boolean value
|
||||
persist_write_bool(key, large_font_size);
|
||||
```
|
||||
|
||||
```c
|
||||
// Read the boolean value
|
||||
bool large_font_size = persist_read_bool(key);
|
||||
```
|
||||
|
||||
|
||||
### Integers
|
||||
|
||||
```c
|
||||
uint32_t key = 1;
|
||||
int highscore = 432;
|
||||
```
|
||||
|
||||
```c
|
||||
// Write an integer
|
||||
persist_write_int(key, highscore);
|
||||
```
|
||||
|
||||
```c
|
||||
// Read the integer value
|
||||
int highscore = persist_read_int(key);
|
||||
```
|
||||
|
||||
|
||||
### Strings
|
||||
|
||||
```c
|
||||
uint32_t key = 2;
|
||||
char *string = "Remember this!";
|
||||
```
|
||||
|
||||
```c
|
||||
// Write the string
|
||||
persist_write_string(key, string);
|
||||
```
|
||||
|
||||
```c
|
||||
// Read the string
|
||||
char buffer[32];
|
||||
persist_read_string(key, buffer, sizeof(buffer));
|
||||
```
|
||||
|
||||
|
||||
### Data Structures
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} Data;
|
||||
|
||||
uint32_t key = 3;
|
||||
Data data = (Data) {
|
||||
.a = 32,
|
||||
.b = 45
|
||||
};
|
||||
```
|
||||
|
||||
```c
|
||||
// Write the data structure
|
||||
persist_write_data(key, &data, sizeof(Data));
|
||||
```
|
||||
|
||||
```c
|
||||
// Read the data structure
|
||||
persist_read_data(key, &data, sizeof(Data));
|
||||
```
|
||||
|
||||
> Note: If a persisted data structure's field layout changes between app
|
||||
> versions, the data read may no longer be compatible (see below).
|
||||
|
||||
|
||||
## Versioning Persisted Data
|
||||
|
||||
As already mentioned, automatic app updates will persist data between app
|
||||
versions. However, if the format of persisted data changes in a new app version
|
||||
(or keys change), developers should version their storage scheme and correctly
|
||||
handle version changes appropriately.
|
||||
|
||||
One way to do this is to use an extra persisted integer as the storage scheme's
|
||||
version number. If the scheme changes, simply update the version number and
|
||||
migrate existing data as required. If old data cannot be migrated it should be
|
||||
deleted and replaced with fresh data in the correct scheme from the user. An
|
||||
example is shown below:
|
||||
|
||||
```c
|
||||
const uint32_t storage_version_key = 786;
|
||||
const int current_storage_version = 2;
|
||||
```
|
||||
|
||||
```c
|
||||
// Store the current storage scheme version number
|
||||
persist_write_int(storage_version_key, current_storage_version);
|
||||
```
|
||||
|
||||
In this example, data stored in a key of `12` is now stored in a key of `13` due
|
||||
to a new key being inserted higher up the list of key values.
|
||||
|
||||
```c
|
||||
// The scheme has changed, increment the version number
|
||||
const int current_storage_version = 3;
|
||||
```
|
||||
|
||||
```c
|
||||
static void migrate_storage_data() {
|
||||
// Check the last storage scheme version the app used
|
||||
int last_storage_version = persist_read_int(storage_version_key);
|
||||
|
||||
if (last_storage_version == current_storage_version) {
|
||||
// No migration necessary
|
||||
return;
|
||||
}
|
||||
|
||||
// Migrate data
|
||||
switch(last_storage_version) {
|
||||
case 0:
|
||||
// ...
|
||||
break;
|
||||
case 1:
|
||||
// ...
|
||||
break;
|
||||
case 2: {
|
||||
uint32_t old_highscore_key = 12;
|
||||
uint32_t new_highscore_key = 13;
|
||||
|
||||
// Migrate to scheme version 3
|
||||
int highscore = persist_read_int(old_highscore_key);
|
||||
persist_write_int(new_highscore_key, highscore);
|
||||
|
||||
// Delete old data
|
||||
persist_delete(old_highscore_key);
|
||||
break;
|
||||
}
|
||||
|
||||
// Migration is complete, store the current storage scheme version number
|
||||
persist_write_int(storage_version_key, current_storage_version);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Alternative Method
|
||||
|
||||
In addition to the ``Storage`` API, data can also be persisted using the
|
||||
`localStorage` API in PebbleKit JS, and communicated with the watch over
|
||||
``AppMessage`` when the app is lanched. However, this method uses more power and
|
||||
fails if the watch is not connected to the phone.
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue