@onekeyfe/react-native-async-storage 3.0.7 → 3.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,132 +1,368 @@
|
|
|
1
1
|
package com.asyncstorage
|
|
2
2
|
|
|
3
|
-
import android.
|
|
4
|
-
import android.
|
|
3
|
+
import android.database.Cursor
|
|
4
|
+
import android.database.sqlite.SQLiteStatement
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
5
6
|
import com.facebook.react.bridge.Promise
|
|
6
7
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
8
|
import com.facebook.react.bridge.ReadableArray
|
|
8
|
-
import com.facebook.react.bridge.
|
|
9
|
+
import com.facebook.react.bridge.WritableArray
|
|
9
10
|
import com.facebook.react.module.annotations.ReactModule
|
|
11
|
+
import org.json.JSONObject
|
|
12
|
+
import java.util.concurrent.Executor
|
|
13
|
+
import java.util.concurrent.Executors
|
|
10
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Ported from upstream @react-native-async-storage/async-storage AsyncStorageModule.java
|
|
17
|
+
* Adapted to use Promise (TurboModule) instead of Callback.
|
|
18
|
+
* Uses SQLite via ReactDatabaseSupplier (same as upstream).
|
|
19
|
+
*/
|
|
11
20
|
@ReactModule(name = RNCAsyncStorageModule.NAME)
|
|
12
21
|
class RNCAsyncStorageModule(reactContext: ReactApplicationContext) :
|
|
13
22
|
NativeRNCAsyncStorageSpec(reactContext) {
|
|
14
23
|
|
|
15
24
|
companion object {
|
|
16
25
|
const val NAME = "RNCAsyncStorage"
|
|
17
|
-
|
|
26
|
+
// SQL variable number limit, defined by SQLITE_LIMIT_VARIABLE_NUMBER
|
|
27
|
+
private const val MAX_SQL_KEYS = 999
|
|
18
28
|
}
|
|
19
29
|
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
private val dbSupplier: ReactDatabaseSupplier = ReactDatabaseSupplier.getInstance(reactContext)
|
|
31
|
+
private val executor: Executor = SerialExecutor(Executors.newSingleThreadExecutor())
|
|
32
|
+
@Volatile
|
|
33
|
+
private var shuttingDown = false
|
|
23
34
|
|
|
24
35
|
override fun getName(): String = NAME
|
|
25
36
|
|
|
37
|
+
override fun initialize() {
|
|
38
|
+
super.initialize()
|
|
39
|
+
shuttingDown = false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun invalidate() {
|
|
43
|
+
shuttingDown = true
|
|
44
|
+
dbSupplier.closeDatabase()
|
|
45
|
+
}
|
|
46
|
+
|
|
26
47
|
override fun multiGet(keys: ReadableArray, promise: Promise) {
|
|
27
|
-
|
|
48
|
+
executor.execute {
|
|
28
49
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
if (!ensureDatabase()) {
|
|
51
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Database Error")
|
|
52
|
+
return@execute
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
val columns = arrayOf(ReactDatabaseSupplier.KEY_COLUMN, ReactDatabaseSupplier.VALUE_COLUMN)
|
|
56
|
+
val keysRemaining = HashSet<String>()
|
|
57
|
+
val data: WritableArray = Arguments.createArray()
|
|
58
|
+
|
|
59
|
+
var keyStart = 0
|
|
60
|
+
while (keyStart < keys.size()) {
|
|
61
|
+
val keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS)
|
|
62
|
+
val cursor: Cursor = dbSupplier.get().query(
|
|
63
|
+
ReactDatabaseSupplier.TABLE_CATALYST,
|
|
64
|
+
columns,
|
|
65
|
+
buildKeySelection(keyCount),
|
|
66
|
+
buildKeySelectionArgs(keys, keyStart, keyCount),
|
|
67
|
+
null, null, null
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
keysRemaining.clear()
|
|
71
|
+
try {
|
|
72
|
+
if (cursor.count != keys.size()) {
|
|
73
|
+
for (keyIndex in keyStart until keyStart + keyCount) {
|
|
74
|
+
keysRemaining.add(keys.getString(keyIndex))
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (cursor.moveToFirst()) {
|
|
78
|
+
do {
|
|
79
|
+
val row = Arguments.createArray()
|
|
80
|
+
row.pushString(cursor.getString(0))
|
|
81
|
+
row.pushString(cursor.getString(1))
|
|
82
|
+
data.pushArray(row)
|
|
83
|
+
keysRemaining.remove(cursor.getString(0))
|
|
84
|
+
} while (cursor.moveToNext())
|
|
85
|
+
}
|
|
86
|
+
} finally {
|
|
87
|
+
cursor.close()
|
|
39
88
|
}
|
|
40
|
-
|
|
89
|
+
|
|
90
|
+
for (key in keysRemaining) {
|
|
91
|
+
val row = Arguments.createArray()
|
|
92
|
+
row.pushString(key)
|
|
93
|
+
row.pushNull()
|
|
94
|
+
data.pushArray(row)
|
|
95
|
+
}
|
|
96
|
+
keysRemaining.clear()
|
|
97
|
+
keyStart += MAX_SQL_KEYS
|
|
41
98
|
}
|
|
42
|
-
|
|
99
|
+
|
|
100
|
+
promise.resolve(data)
|
|
43
101
|
} catch (e: Exception) {
|
|
44
102
|
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
45
103
|
}
|
|
46
|
-
}
|
|
104
|
+
}
|
|
47
105
|
}
|
|
48
106
|
|
|
49
107
|
override fun multiSet(keyValuePairs: ReadableArray, promise: Promise) {
|
|
50
|
-
|
|
108
|
+
if (keyValuePairs.size() == 0) {
|
|
109
|
+
promise.resolve(null)
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
executor.execute {
|
|
51
114
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
115
|
+
if (!ensureDatabase()) {
|
|
116
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Database Error")
|
|
117
|
+
return@execute
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
val sql = "INSERT OR REPLACE INTO ${ReactDatabaseSupplier.TABLE_CATALYST} VALUES (?, ?);"
|
|
121
|
+
val statement: SQLiteStatement = dbSupplier.get().compileStatement(sql)
|
|
122
|
+
try {
|
|
123
|
+
dbSupplier.get().beginTransaction()
|
|
124
|
+
for (idx in 0 until keyValuePairs.size()) {
|
|
125
|
+
val pair = keyValuePairs.getArray(idx)
|
|
126
|
+
if (pair == null || pair.size() != 2) {
|
|
127
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value")
|
|
128
|
+
return@execute
|
|
129
|
+
}
|
|
56
130
|
val key = pair.getString(0)
|
|
57
131
|
val value = pair.getString(1)
|
|
58
|
-
|
|
132
|
+
if (key == null) {
|
|
133
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Invalid key")
|
|
134
|
+
return@execute
|
|
135
|
+
}
|
|
136
|
+
if (value == null) {
|
|
137
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value")
|
|
138
|
+
return@execute
|
|
139
|
+
}
|
|
140
|
+
statement.clearBindings()
|
|
141
|
+
statement.bindString(1, key)
|
|
142
|
+
statement.bindString(2, value)
|
|
143
|
+
statement.execute()
|
|
144
|
+
}
|
|
145
|
+
dbSupplier.get().setTransactionSuccessful()
|
|
146
|
+
} finally {
|
|
147
|
+
try {
|
|
148
|
+
dbSupplier.get().endTransaction()
|
|
149
|
+
} catch (e: Exception) {
|
|
150
|
+
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
151
|
+
return@execute
|
|
59
152
|
}
|
|
60
153
|
}
|
|
61
|
-
editor.apply()
|
|
62
154
|
promise.resolve(null)
|
|
63
155
|
} catch (e: Exception) {
|
|
64
156
|
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
65
157
|
}
|
|
66
|
-
}
|
|
158
|
+
}
|
|
67
159
|
}
|
|
68
160
|
|
|
69
161
|
override fun multiRemove(keys: ReadableArray, promise: Promise) {
|
|
70
|
-
|
|
162
|
+
if (keys.size() == 0) {
|
|
163
|
+
promise.resolve(null)
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
executor.execute {
|
|
71
168
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
169
|
+
if (!ensureDatabase()) {
|
|
170
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Database Error")
|
|
171
|
+
return@execute
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
dbSupplier.get().beginTransaction()
|
|
176
|
+
var keyStart = 0
|
|
177
|
+
while (keyStart < keys.size()) {
|
|
178
|
+
val keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS)
|
|
179
|
+
dbSupplier.get().delete(
|
|
180
|
+
ReactDatabaseSupplier.TABLE_CATALYST,
|
|
181
|
+
buildKeySelection(keyCount),
|
|
182
|
+
buildKeySelectionArgs(keys, keyStart, keyCount)
|
|
183
|
+
)
|
|
184
|
+
keyStart += MAX_SQL_KEYS
|
|
185
|
+
}
|
|
186
|
+
dbSupplier.get().setTransactionSuccessful()
|
|
187
|
+
} finally {
|
|
188
|
+
try {
|
|
189
|
+
dbSupplier.get().endTransaction()
|
|
190
|
+
} catch (e: Exception) {
|
|
191
|
+
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
192
|
+
return@execute
|
|
193
|
+
}
|
|
75
194
|
}
|
|
76
|
-
editor.apply()
|
|
77
195
|
promise.resolve(null)
|
|
78
196
|
} catch (e: Exception) {
|
|
79
197
|
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
80
198
|
}
|
|
81
|
-
}
|
|
199
|
+
}
|
|
82
200
|
}
|
|
83
201
|
|
|
84
202
|
override fun multiMerge(keyValuePairs: ReadableArray, promise: Promise) {
|
|
85
|
-
|
|
203
|
+
executor.execute {
|
|
86
204
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
205
|
+
if (!ensureDatabase()) {
|
|
206
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Database Error")
|
|
207
|
+
return@execute
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
dbSupplier.get().beginTransaction()
|
|
212
|
+
for (idx in 0 until keyValuePairs.size()) {
|
|
213
|
+
val pair = keyValuePairs.getArray(idx)
|
|
214
|
+
if (pair == null || pair.size() != 2) {
|
|
215
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value")
|
|
216
|
+
return@execute
|
|
217
|
+
}
|
|
92
218
|
val key = pair.getString(0)
|
|
93
219
|
val value = pair.getString(1)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
220
|
+
if (key == null) {
|
|
221
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Invalid key")
|
|
222
|
+
return@execute
|
|
223
|
+
}
|
|
224
|
+
if (value == null) {
|
|
225
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value")
|
|
226
|
+
return@execute
|
|
227
|
+
}
|
|
228
|
+
if (!mergeImpl(key, value)) {
|
|
229
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Database Error")
|
|
230
|
+
return@execute
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
dbSupplier.get().setTransactionSuccessful()
|
|
234
|
+
} finally {
|
|
235
|
+
try {
|
|
236
|
+
dbSupplier.get().endTransaction()
|
|
237
|
+
} catch (e: Exception) {
|
|
238
|
+
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
239
|
+
return@execute
|
|
97
240
|
}
|
|
98
241
|
}
|
|
99
|
-
editor.apply()
|
|
100
242
|
promise.resolve(null)
|
|
101
243
|
} catch (e: Exception) {
|
|
102
244
|
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
103
245
|
}
|
|
104
|
-
}
|
|
246
|
+
}
|
|
105
247
|
}
|
|
106
248
|
|
|
107
249
|
override fun getAllKeys(promise: Promise) {
|
|
108
|
-
|
|
250
|
+
executor.execute {
|
|
109
251
|
try {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
252
|
+
if (!ensureDatabase()) {
|
|
253
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Database Error")
|
|
254
|
+
return@execute
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
val columns = arrayOf(ReactDatabaseSupplier.KEY_COLUMN)
|
|
258
|
+
val cursor: Cursor = dbSupplier.get().query(
|
|
259
|
+
ReactDatabaseSupplier.TABLE_CATALYST,
|
|
260
|
+
columns, null, null, null, null, null
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
val data: WritableArray = Arguments.createArray()
|
|
264
|
+
try {
|
|
265
|
+
if (cursor.moveToFirst()) {
|
|
266
|
+
do {
|
|
267
|
+
data.pushString(cursor.getString(0))
|
|
268
|
+
} while (cursor.moveToNext())
|
|
269
|
+
}
|
|
270
|
+
} finally {
|
|
271
|
+
cursor.close()
|
|
114
272
|
}
|
|
115
|
-
promise.resolve(
|
|
273
|
+
promise.resolve(data)
|
|
116
274
|
} catch (e: Exception) {
|
|
117
275
|
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
118
276
|
}
|
|
119
|
-
}
|
|
277
|
+
}
|
|
120
278
|
}
|
|
121
279
|
|
|
122
280
|
override fun clear(promise: Promise) {
|
|
123
|
-
|
|
281
|
+
executor.execute {
|
|
124
282
|
try {
|
|
125
|
-
|
|
283
|
+
if (!dbSupplier.ensureDatabase()) {
|
|
284
|
+
promise.reject("ASYNC_STORAGE_ERROR", "Database Error")
|
|
285
|
+
return@execute
|
|
286
|
+
}
|
|
287
|
+
dbSupplier.clear()
|
|
126
288
|
promise.resolve(null)
|
|
127
289
|
} catch (e: Exception) {
|
|
128
290
|
promise.reject("ASYNC_STORAGE_ERROR", e.message, e)
|
|
129
291
|
}
|
|
130
|
-
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// --- Private helpers (ported from AsyncLocalStorageUtil.java) ---
|
|
296
|
+
|
|
297
|
+
private fun ensureDatabase(): Boolean {
|
|
298
|
+
return !shuttingDown && dbSupplier.ensureDatabase()
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private fun buildKeySelection(count: Int): String {
|
|
302
|
+
val list = Array(count) { "?" }
|
|
303
|
+
return "${ReactDatabaseSupplier.KEY_COLUMN} IN (${list.joinToString(", ")})"
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private fun buildKeySelectionArgs(keys: ReadableArray, start: Int, count: Int): Array<String> {
|
|
307
|
+
return Array(count) { keys.getString(start + it) }
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private fun getItemImpl(key: String): String? {
|
|
311
|
+
val columns = arrayOf(ReactDatabaseSupplier.VALUE_COLUMN)
|
|
312
|
+
val selectionArgs = arrayOf(key)
|
|
313
|
+
val cursor = dbSupplier.get().query(
|
|
314
|
+
ReactDatabaseSupplier.TABLE_CATALYST,
|
|
315
|
+
columns,
|
|
316
|
+
"${ReactDatabaseSupplier.KEY_COLUMN}=?",
|
|
317
|
+
selectionArgs,
|
|
318
|
+
null, null, null
|
|
319
|
+
)
|
|
320
|
+
try {
|
|
321
|
+
return if (!cursor.moveToFirst()) null else cursor.getString(0)
|
|
322
|
+
} finally {
|
|
323
|
+
cursor.close()
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private fun setItemImpl(key: String, value: String): Boolean {
|
|
328
|
+
val contentValues = android.content.ContentValues()
|
|
329
|
+
contentValues.put(ReactDatabaseSupplier.KEY_COLUMN, key)
|
|
330
|
+
contentValues.put(ReactDatabaseSupplier.VALUE_COLUMN, value)
|
|
331
|
+
val inserted = dbSupplier.get().insertWithOnConflict(
|
|
332
|
+
ReactDatabaseSupplier.TABLE_CATALYST,
|
|
333
|
+
null,
|
|
334
|
+
contentValues,
|
|
335
|
+
android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE
|
|
336
|
+
)
|
|
337
|
+
return inserted != -1L
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private fun mergeImpl(key: String, value: String): Boolean {
|
|
341
|
+
val oldValue = getItemImpl(key)
|
|
342
|
+
val newValue: String
|
|
343
|
+
if (oldValue == null) {
|
|
344
|
+
newValue = value
|
|
345
|
+
} else {
|
|
346
|
+
val oldJSON = JSONObject(oldValue)
|
|
347
|
+
val newJSON = JSONObject(value)
|
|
348
|
+
deepMergeInto(oldJSON, newJSON)
|
|
349
|
+
newValue = oldJSON.toString()
|
|
350
|
+
}
|
|
351
|
+
return setItemImpl(key, newValue)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
private fun deepMergeInto(oldJSON: JSONObject, newJSON: JSONObject) {
|
|
355
|
+
val keys = newJSON.keys()
|
|
356
|
+
while (keys.hasNext()) {
|
|
357
|
+
val key = keys.next()
|
|
358
|
+
val newJSONObject = newJSON.optJSONObject(key)
|
|
359
|
+
val oldJSONObject = oldJSON.optJSONObject(key)
|
|
360
|
+
if (newJSONObject != null && oldJSONObject != null) {
|
|
361
|
+
deepMergeInto(oldJSONObject, newJSONObject)
|
|
362
|
+
oldJSON.put(key, oldJSONObject)
|
|
363
|
+
} else {
|
|
364
|
+
oldJSON.put(key, newJSON.get(key))
|
|
365
|
+
}
|
|
366
|
+
}
|
|
131
367
|
}
|
|
132
368
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
package com.asyncstorage;
|
|
9
|
+
|
|
10
|
+
import android.content.Context;
|
|
11
|
+
import android.database.sqlite.SQLiteDatabase;
|
|
12
|
+
import android.database.sqlite.SQLiteException;
|
|
13
|
+
import android.database.sqlite.SQLiteOpenHelper;
|
|
14
|
+
import android.util.Log;
|
|
15
|
+
import javax.annotation.Nullable;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Database supplier of the database used by react native async storage.
|
|
19
|
+
* Ported from upstream @react-native-async-storage/async-storage ReactDatabaseSupplier.java.
|
|
20
|
+
*/
|
|
21
|
+
public class ReactDatabaseSupplier extends SQLiteOpenHelper {
|
|
22
|
+
|
|
23
|
+
public static final String DATABASE_NAME = "RKStorage";
|
|
24
|
+
|
|
25
|
+
private static final int DATABASE_VERSION = 1;
|
|
26
|
+
private static final int SLEEP_TIME_MS = 30;
|
|
27
|
+
|
|
28
|
+
static final String TABLE_CATALYST = "catalystLocalStorage";
|
|
29
|
+
static final String KEY_COLUMN = "key";
|
|
30
|
+
static final String VALUE_COLUMN = "value";
|
|
31
|
+
|
|
32
|
+
static final String VERSION_TABLE_CREATE =
|
|
33
|
+
"CREATE TABLE " + TABLE_CATALYST + " (" +
|
|
34
|
+
KEY_COLUMN + " TEXT PRIMARY KEY, " +
|
|
35
|
+
VALUE_COLUMN + " TEXT NOT NULL" +
|
|
36
|
+
")";
|
|
37
|
+
|
|
38
|
+
private static @Nullable ReactDatabaseSupplier sReactDatabaseSupplierInstance;
|
|
39
|
+
|
|
40
|
+
private Context mContext;
|
|
41
|
+
private @Nullable SQLiteDatabase mDb;
|
|
42
|
+
private long mMaximumDatabaseSize = 6L * 1024L * 1024L;
|
|
43
|
+
|
|
44
|
+
private ReactDatabaseSupplier(Context context) {
|
|
45
|
+
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
|
46
|
+
mContext = context;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public static ReactDatabaseSupplier getInstance(Context context) {
|
|
50
|
+
if (sReactDatabaseSupplierInstance == null) {
|
|
51
|
+
sReactDatabaseSupplierInstance = new ReactDatabaseSupplier(context.getApplicationContext());
|
|
52
|
+
}
|
|
53
|
+
return sReactDatabaseSupplierInstance;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@Override
|
|
57
|
+
public void onCreate(SQLiteDatabase db) {
|
|
58
|
+
db.execSQL(VERSION_TABLE_CREATE);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Override
|
|
62
|
+
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
|
63
|
+
if (oldVersion != newVersion) {
|
|
64
|
+
deleteDatabase();
|
|
65
|
+
onCreate(db);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
synchronized boolean ensureDatabase() {
|
|
70
|
+
if (mDb != null && mDb.isOpen()) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
SQLiteException lastSQLiteException = null;
|
|
74
|
+
for (int tries = 0; tries < 2; tries++) {
|
|
75
|
+
try {
|
|
76
|
+
if (tries > 0) {
|
|
77
|
+
deleteDatabase();
|
|
78
|
+
}
|
|
79
|
+
mDb = getWritableDatabase();
|
|
80
|
+
break;
|
|
81
|
+
} catch (SQLiteException e) {
|
|
82
|
+
lastSQLiteException = e;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
Thread.sleep(SLEEP_TIME_MS);
|
|
86
|
+
} catch (InterruptedException ie) {
|
|
87
|
+
Thread.currentThread().interrupt();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (mDb == null) {
|
|
91
|
+
throw lastSQLiteException;
|
|
92
|
+
}
|
|
93
|
+
mDb.setMaximumSize(mMaximumDatabaseSize);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public synchronized SQLiteDatabase get() {
|
|
98
|
+
ensureDatabase();
|
|
99
|
+
return mDb;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public synchronized void clearAndCloseDatabase() throws RuntimeException {
|
|
103
|
+
try {
|
|
104
|
+
clear();
|
|
105
|
+
closeDatabase();
|
|
106
|
+
} catch (Exception e) {
|
|
107
|
+
if (deleteDatabase()) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
throw new RuntimeException("Clearing and deleting database " + DATABASE_NAME + " failed");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
synchronized void clear() {
|
|
115
|
+
get().delete(TABLE_CATALYST, null, null);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public synchronized void setMaximumSize(long size) {
|
|
119
|
+
mMaximumDatabaseSize = size;
|
|
120
|
+
if (mDb != null) {
|
|
121
|
+
mDb.setMaximumSize(mMaximumDatabaseSize);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private synchronized boolean deleteDatabase() {
|
|
126
|
+
closeDatabase();
|
|
127
|
+
return mContext.deleteDatabase(DATABASE_NAME);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public synchronized void closeDatabase() {
|
|
131
|
+
if (mDb != null && mDb.isOpen()) {
|
|
132
|
+
mDb.close();
|
|
133
|
+
mDb = null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public static void deleteInstance() {
|
|
138
|
+
sReactDatabaseSupplierInstance = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
package com.asyncstorage;
|
|
2
|
+
|
|
3
|
+
import java.util.ArrayDeque;
|
|
4
|
+
import java.util.concurrent.Executor;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Ported from upstream @react-native-async-storage/async-storage SerialExecutor.java.
|
|
8
|
+
*/
|
|
9
|
+
public class SerialExecutor implements Executor {
|
|
10
|
+
private final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
|
|
11
|
+
private Runnable mActive;
|
|
12
|
+
private final Executor executor;
|
|
13
|
+
|
|
14
|
+
public SerialExecutor(Executor executor) {
|
|
15
|
+
this.executor = executor;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public synchronized void execute(final Runnable r) {
|
|
19
|
+
mTasks.offer(new Runnable() {
|
|
20
|
+
public void run() {
|
|
21
|
+
try {
|
|
22
|
+
r.run();
|
|
23
|
+
} finally {
|
|
24
|
+
scheduleNext();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
if (mActive == null) {
|
|
29
|
+
scheduleNext();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
synchronized void scheduleNext() {
|
|
34
|
+
if ((mActive = mTasks.poll()) != null) {
|
|
35
|
+
executor.execute(mActive);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|