Skip to content

Commit 4ea1957

Browse files
mehmetfPark Sung Min
authored andcommitted
[shared_preferences] Allow getInstance() to be reentrant (flutter#1961)
1 parent 4f10518 commit 4ea1957

2 files changed

Lines changed: 24 additions & 8 deletions

File tree

packages/shared_preferences/lib/shared_preferences.dart

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,24 @@ class SharedPreferences {
1818
SharedPreferences._(this._preferenceCache);
1919

2020
static const String _prefix = 'flutter.';
21-
static SharedPreferences _instance;
21+
static Completer<SharedPreferences> _completer;
2222
static Future<SharedPreferences> getInstance() async {
23-
if (_instance == null) {
24-
final Map<String, Object> preferencesMap =
25-
await _getSharedPreferencesMap();
26-
_instance = SharedPreferences._(preferencesMap);
23+
if (_completer == null) {
24+
_completer = Completer<SharedPreferences>();
25+
try {
26+
final Map<String, Object> preferencesMap =
27+
await _getSharedPreferencesMap();
28+
_completer.complete(SharedPreferences._(preferencesMap));
29+
} on Exception catch (e) {
30+
// If there's an error, explicitly return the future with an error.
31+
// then set the completer to null so we can retry.
32+
_completer.completeError(e);
33+
final Future<SharedPreferences> sharedPrefsFuture = _completer.future;
34+
_completer = null;
35+
return sharedPrefsFuture;
36+
}
2737
}
28-
return _instance;
38+
return _completer.future;
2939
}
3040

3141
/// The cache that holds all preferences.
@@ -168,7 +178,7 @@ class SharedPreferences {
168178

169179
/// Initializes the shared preferences with mock values for testing.
170180
///
171-
/// If the singleton instance has been initialized already, it is automatically reloaded.
181+
/// If the singleton instance has been initialized already, it is nullified.
172182
@visibleForTesting
173183
static void setMockInitialValues(Map<String, dynamic> values) {
174184
_kChannel.setMockMethodCallHandler((MethodCall methodCall) async {
@@ -177,6 +187,6 @@ class SharedPreferences {
177187
}
178188
return null;
179189
});
180-
_instance?.reload();
190+
_completer = null;
181191
}
182192
}

packages/shared_preferences/test/shared_preferences_test.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ void main() {
155155
expect(preferences.getString('String'), kTestValues2['flutter.String']);
156156
});
157157

158+
test('back to back calls should return same instance.', () async {
159+
final Future<SharedPreferences> first = SharedPreferences.getInstance();
160+
final Future<SharedPreferences> second = SharedPreferences.getInstance();
161+
expect(await first, await second);
162+
});
163+
158164
group('mocking', () {
159165
const String _key = 'dummy';
160166
const String _prefixedKey = 'flutter.' + _key;

0 commit comments

Comments
 (0)