Skip to content

Commit 0c2ca34

Browse files
author
Krzysztof Borowy
committed
docs: document feature, brownfield integration
1 parent d8b235c commit 0c2ca34

File tree

6 files changed

+213
-4
lines changed

6 files changed

+213
-4
lines changed

website/docs/Linking.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ sidebar_label: Manual linking
55
---
66

77

8-
98
## iOS
109

1110
#### Project linking

website/docs/advanced/BrownfieldIntegration.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import PlatformSupport from "../../src/components/Platform.js"
77

88
**Supported platforms:**
99
<PlatformSupport title="iOS/MacOS" platformIcon="icon_ios.svg"></PlatformSupport>
10+
<PlatformSupport title="Android" platformIcon="icon_android.svg"></PlatformSupport>
1011

1112
---
1213

14+
# iOS
15+
1316
If you're embedding React Native into native application, you can also integrate
1417
Async Storage module, so that both worlds will use one storage solution.
1518

@@ -110,3 +113,119 @@ Called by `getItem` and `multiGet` in JS.
110113
**Optional:** Returns whether the delegate should be treated as a passthrough.
111114
This is useful for monitoring storage usage among other things. Returns `NO` by
112115
default.
116+
117+
---
118+
119+
# Android
120+
121+
The recommended approach here is to use Kotlin language to leverage coroutines when accessing the storage.
122+
Java is also supported (through Kotlin interop), but the approach is more cumbersome.
123+
124+
125+
## Prerequisites
126+
127+
1. [Next storage feature](Next.md) enabled.
128+
2. Add dependency on `coroutines-android` in your app's `build.gradle`
129+
130+
```diff
131+
132+
dependencies {
133+
// other dependencies
134+
135+
136+
// will work with coroutines 1.3.0 and up
137+
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
138+
139+
}
140+
```
141+
142+
3. Your library of choice for parsing JSON storage values (since there are strings only)
143+
144+
145+
## Access storage
146+
147+
### Kotlin (recommended)
148+
149+
We use Coroutines to handle asynchronous code. Each method on storage is `suspend` method, so you need to
150+
call it from within a coroutine.
151+
152+
153+
#### Reading value
154+
155+
```kotlin
156+
suspend fun readValue(ctx: Context, keys: List<String>) {
157+
// get instance of the Storage by providing context object
158+
val asyncStorage = StorageModule.getStorageInstance(ctx)
159+
160+
val entries: List<Entry> = asyncStorage.getValues(keys)
161+
doSomethingWithValues(entries)
162+
}
163+
```
164+
165+
#### Saving value
166+
167+
```kotlin
168+
suspend fun saveValue(ctx: Context) {
169+
val asyncStorage = StorageModule.getStorageInstance(ctx)
170+
171+
val entries = listOf(
172+
Entry("myKey", "myValue")
173+
)
174+
asyncStorage.setValues(entries)
175+
}
176+
```
177+
178+
179+
### Java
180+
181+
You can access AsyncStorage form Java, but you're still required to add Kotlin dependencies.
182+
There's no one way of accessing the data and there's more than one way to parse it.
183+
184+
185+
#### Reading from storage
186+
187+
```java
188+
void readStorageValue(Context ctx, String key) {
189+
AsyncStorageAccess asyncStorage = StorageModule.getStorageInstance(ctx);
190+
191+
BuildersKt.launch(GlobalScope.INSTANCE,
192+
Dispatchers.getIO(),
193+
CoroutineStart.DEFAULT,
194+
(scope, continuation) -> {
195+
List<String> keys = new ArrayList<>();
196+
keys.add(key);
197+
198+
List<Entry> entries = (List<Entry>) asyncStorage.getValues(keys, (Continuation<? super List<? extends Entry>>) continuation);
199+
doSomethingWithValues(entries);
200+
201+
return Unit.INSTANCE;
202+
});
203+
204+
}
205+
```
206+
207+
208+
#### Saving to storage
209+
210+
```java
211+
void saveStorageValue(Context ctx, String key, String value) {
212+
AsyncStorageAccess asyncStorage = StorageModule.getStorageInstance(ctx);
213+
214+
BuildersKt.launch(GlobalScope.INSTANCE,
215+
Dispatchers.getIO(),
216+
CoroutineStart.DEFAULT,
217+
(scope, continuation) -> {
218+
219+
List<Entry> entries = new ArrayList<>();
220+
Entry entry = new Entry(key, value);
221+
entries.add(entry);
222+
223+
asyncStorage.setValues(entries, continuation);
224+
225+
return Unit.INSTANCE;
226+
});
227+
}
228+
```
229+
230+
231+

website/docs/advanced/DedicatedExecutor.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import PlatformSupport from "../../src/components/Platform.js"
1010

1111
---
1212

13-
This feature would be mostly used in brownfield apps and [in edge cases with some android devices.](https://github.com/react-native-async-storage/async-storage/issues/159)
13+
**Note**: This feature is obsolete when [Next storage feature is enabled](Next.md).
14+
1415

1516
## Motivation
1617

18+
This feature would be mostly used in brownfield apps and [in edge cases with some android devices.](https://github.com/react-native-async-storage/async-storage/issues/159)
1719
Dedicated thread pool executor makes `AsyncStorage` use separate thread pool for its tasks execution.
1820

1921
Use this feature if `THREAD_POOL_EXECUTOR` from `AsyncTasks`:

website/docs/advanced/IncreaseDbSize.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ import PlatformSupport from "../../src/components/Platform.js"
1010

1111
---
1212

13+
**Note**: This feature is obsolete when [Next storage feature is enabled](Next.md).
14+
15+
## Motivation
16+
1317
Current Async Storage's size is set to 6MB. Going over this limit causes `database or disk is full` error. This 6MB limit is a sane limit to protect the user from the app storing too much data in the database. This also protects the database from filling up the disk cache and becoming malformed (endTransaction() calls will throw an exception, not rollback, and leave the db malformed). You have to be aware of that risk when increasing the database size. We recommend to ensure that your app does not write more data to AsyncStorage than space is left on disk. Since AsyncStorage is based on SQLite on Android you also have to be aware of the [SQLite limits](https://www.sqlite.org/limits.html).
1418

15-
### Increase limit
19+
## Increase limit
1620

1721
Add a `AsyncStorage_db_size_in_MB` property to your `android/gradle.properties`:
1822

website/docs/advanced/Next.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
id: next
3+
title: Next storage implementation
4+
sidebar_label: Next storage implementation
5+
---
6+
import PlatformSupport from "../../src/components/Platform.js"
7+
8+
**Supported platforms:**
9+
<PlatformSupport title="Android" platformIcon="icon_android.svg"></PlatformSupport>
10+
11+
---
12+
13+
### Motivation
14+
15+
Current implementation of persistence layer is created using [SQLiteOpenHelper](https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper),
16+
a helper class that manages database creation and migrations. Even if this approach is powerful, the lack of compile time query verification and a big boilerplate of mapping SQLite queries to actual values make this implementation prone to many errors.
17+
18+
This Async Storage feature improves the persistence layer, using modern approaches to access SQLite (using [Room](https://developer.android.com/training/data-storage/room)), to reduce possible anomalies to the minimum.
19+
On top of that, it allows to access Async Storage from the native side, useful in [Brownfield integration.](BrownfieldIntegration.md#android)
20+
21+
### Migration
22+
23+
This feature requires no migration from the developer perspective - the current database will be recreated (based on the current one), meaning user won't lose any data if you decide to opt in.
24+
There's a small drawback to know - the database "recreation" happens **only once**. Unless you want to disable the feature in the future, there's nothing to worry about.
25+
26+
#### How it works
27+
28+
The new database (the one used by this feature) will be created based on the current database file, if the new one does not exist yet.
29+
If we detect that there's already the new database on the device, recreation will not kick in.
30+
31+
32+
#### Why is it important
33+
34+
Let's say you enabled the feature for the first time - recreation kicks in and the old database file is untouched.
35+
If you decide to disable the feature, your users will be back using old database. No data migrations is happening from new to old database file.
36+
When you enable the feature again, the new database is **not** recreated, because it already exists, and no data is copied over.
37+
38+
39+
### Enabling
40+
41+
1. In your project's `android` directory, locate root `build.gradle` file. Add Kotlin dependency to the `buildscript`:
42+
43+
```diff
44+
buildscript {
45+
ext {
46+
// other extensions
47+
+ kotlinVersion = '1.4.21'
48+
}
49+
50+
dependencies {
51+
// other dependencies
52+
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
53+
}
54+
}
55+
56+
```
57+
58+
2. In the same directory (normally `android`) locate `gradle.properties` file (if does not exists, create one) and add the line:
59+
60+
```groovy
61+
AsyncStorage_useNextStorage=true
62+
```
63+
64+
**How to specifying Kotlin version**
65+
66+
Supported Kotlin versions are `1.4.x`. You can specify which one to use in two ways:
67+
68+
- having an `kotlinVersion` extension on the `rootProject` (recommended):
69+
70+
```groovy
71+
rootProject.ext.kotlinVersion = '1.4.21'
72+
```
73+
74+
- specify `AsyncStorage_kotlinVersion` in `gradle.properties`:
75+
76+
```groovy
77+
AsyncStorage_kotlinVersion=1.4.21
78+
```
79+
80+
### Notable changes
81+
82+
Alongside of a warning regarding `key`/`value`, errors are thrown when:
83+
84+
- Your `key` is `null` or `not a string`
85+
- You provide value that is `not a string`

website/sidebars.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
docs: {
33
'Getting started': ['install', 'usage', 'link', 'api'],
4-
Advanced: ['advanced/jest', 'advanced/brownfield', 'advanced/backup', 'advanced/executor', 'advanced/db_size'],
4+
Advanced: ['advanced/next', 'advanced/jest', 'advanced/brownfield', 'advanced/backup', 'advanced/executor', 'advanced/db_size'],
55
Help: ['help/troubleshooting'],
66
},
77
};

0 commit comments

Comments
 (0)