15
15
16
16
package com .amplifyframework .datastore ;
17
17
18
+ import android .annotation .SuppressLint ;
18
19
import android .content .Context ;
19
20
import androidx .annotation .NonNull ;
20
21
import androidx .annotation .Nullable ;
65
66
import java .util .concurrent .TimeUnit ;
66
67
67
68
import io .reactivex .rxjava3 .core .Completable ;
69
+ import io .reactivex .rxjava3 .disposables .CompositeDisposable ;
70
+ import io .reactivex .rxjava3 .disposables .Disposable ;
68
71
import io .reactivex .rxjava3 .schedulers .Schedulers ;
69
72
70
73
/**
71
74
* An AWS implementation of the {@link DataStorePlugin}.
72
75
*/
76
+ @ SuppressLint ("RxLeakedSubscription" )
73
77
public final class AWSDataStorePlugin extends DataStorePlugin <Void > {
74
78
private static final Logger LOG = Amplify .Logging .logger (CategoryType .DATASTORE , "amplify:aws-datastore" );
75
79
private static final long LIFECYCLE_TIMEOUT_MS = TimeUnit .SECONDS .toMillis (5 );
@@ -98,6 +102,12 @@ public final class AWSDataStorePlugin extends DataStorePlugin<Void> {
98
102
99
103
private final ReachabilityMonitor reachabilityMonitor ;
100
104
105
+ // Subscriptions that should be disposed when datastore is stopped
106
+ private final CompositeDisposable startedDisposables = new CompositeDisposable ();
107
+
108
+ // Subscriptions that have the same lifetime as the plugin
109
+ private final CompositeDisposable pluginDisposables = new CompositeDisposable ();
110
+
101
111
private AWSDataStorePlugin (
102
112
@ NonNull ModelProvider modelProvider ,
103
113
@ NonNull SchemaRegistry schemaRegistry ,
@@ -286,7 +296,11 @@ private void configure(Context context, DataStoreConfiguration configuration) {
286
296
287
297
reachabilityMonitor .configure (context );
288
298
289
- waitForInitialization ().subscribe (this ::observeNetworkStatus );
299
+ Disposable subscription = waitForInitialization ().subscribe (
300
+ this ::observeNetworkStatus ,
301
+ error -> LOG .error ("Datastore did not initialize" , error )
302
+ );
303
+ pluginDisposables .add (subscription );
290
304
}
291
305
292
306
private void publishNetworkStatusEvent (boolean active ) {
@@ -295,16 +309,27 @@ private void publishNetworkStatusEvent(boolean active) {
295
309
}
296
310
297
311
private void observeNetworkStatus () {
298
- reachabilityMonitor .getObservable ()
299
- .subscribe (this ::publishNetworkStatusEvent );
312
+ Disposable subscription = reachabilityMonitor .getObservable ()
313
+ .subscribe (
314
+ this ::publishNetworkStatusEvent ,
315
+ error -> LOG .warn ("Unable to subscribe to network status events" , error )
316
+ );
317
+ pluginDisposables .add (subscription );
300
318
}
301
319
320
+ @ SuppressLint ("CheckResult" )
302
321
@ WorkerThread
303
322
@ Override
304
323
public void initialize (@ NonNull Context context ) throws AmplifyException {
305
324
try {
306
- initializeStorageAdapter (context )
307
- .blockingAwait (LIFECYCLE_TIMEOUT_MS , TimeUnit .MILLISECONDS );
325
+ boolean initialized = initializeStorageAdapter (context )
326
+ .blockingAwait (LIFECYCLE_TIMEOUT_MS , TimeUnit .MILLISECONDS );
327
+ if (!initialized ) {
328
+ throw new DataStoreException (
329
+ "Storage adapter did not initialize within allotted timeout" ,
330
+ AmplifyException .REPORT_BUG_TO_AWS_SUGGESTION
331
+ );
332
+ }
308
333
} catch (Throwable initError ) {
309
334
throw new AmplifyException (
310
335
"Failed to initialize the local storage adapter for the DataStore plugin." ,
@@ -327,8 +352,8 @@ private Completable initializeStorageAdapter(Context context) {
327
352
}
328
353
329
354
private Completable waitForInitialization () {
330
- return Completable .fromAction (() -> categoryInitializationsPending . await () )
331
- .timeout (LIFECYCLE_TIMEOUT_MS , TimeUnit .MILLISECONDS )
355
+ return Completable .fromAction (categoryInitializationsPending :: await )
356
+ .timeout (LIFECYCLE_TIMEOUT_MS , TimeUnit .MILLISECONDS , Schedulers . io () )
332
357
.subscribeOn (Schedulers .io ())
333
358
.doOnComplete (() -> LOG .info ("DataStore plugin initialized." ))
334
359
.doOnError (error -> LOG .error ("DataStore initialization timed out." , error ));
@@ -339,27 +364,30 @@ private Completable waitForInitialization() {
339
364
*/
340
365
@ Override
341
366
public void start (@ NonNull Action onComplete , @ NonNull Consumer <DataStoreException > onError ) {
342
- waitForInitialization ()
367
+ Disposable subscription = waitForInitialization ()
343
368
.andThen (orchestrator .start ())
344
369
.subscribeOn (Schedulers .io ())
345
370
.subscribe (
346
371
onComplete ::call ,
347
372
error -> onError .accept (new DataStoreException ("Failed to start DataStore." , error , "Retry." ))
348
373
);
374
+ startedDisposables .add (subscription );
349
375
}
350
376
351
377
/**
352
378
* {@inheritDoc}
353
379
*/
354
380
@ Override
355
381
public void stop (@ NonNull Action onComplete , @ NonNull Consumer <DataStoreException > onError ) {
356
- waitForInitialization ()
382
+ startedDisposables .dispose ();
383
+ Disposable subscription = waitForInitialization ()
357
384
.andThen (orchestrator .stop ())
358
385
.subscribeOn (Schedulers .io ())
359
386
.subscribe (
360
387
onComplete ::call ,
361
388
error -> onError .accept (new DataStoreException ("Failed to stop DataStore." , error , "Retry." ))
362
389
);
390
+ startedDisposables .add (subscription );
363
391
}
364
392
365
393
/**
@@ -372,12 +400,19 @@ public void stop(@NonNull Action onComplete, @NonNull Consumer<DataStoreExceptio
372
400
*/
373
401
@ Override
374
402
public void clear (@ NonNull Action onComplete , @ NonNull Consumer <DataStoreException > onError ) {
375
- stop (() -> Completable .create (emitter -> sqliteStorageAdapter .clear (emitter ::onComplete , emitter ::onError ))
376
- .subscribeOn (Schedulers .io ())
377
- .subscribe (onComplete ::call ,
378
- throwable -> onError .accept (new DataStoreException ("Clear operation failed" ,
379
- throwable , AmplifyException .REPORT_BUG_TO_AWS_SUGGESTION ))),
380
- onError );
403
+ stop (
404
+ () -> {
405
+ Disposable completable = Completable .create (
406
+ emitter -> sqliteStorageAdapter .clear (emitter ::onComplete , emitter ::onError )
407
+ )
408
+ .subscribeOn (Schedulers .io ())
409
+ .subscribe (onComplete ::call ,
410
+ throwable -> onError .accept (new DataStoreException ("Clear operation failed" ,
411
+ throwable , AmplifyException .REPORT_BUG_TO_AWS_SUGGESTION )));
412
+ pluginDisposables .add (completable );
413
+ },
414
+ onError
415
+ );
381
416
}
382
417
383
418
/**
0 commit comments