Skip to content

Commit 4dea720

Browse files
[shared_preferences] Fix concurrent modification of the shared preferences on Android (flutter#3684)
Uses an actual queue, rather than a one-element handoff "queue", for the single-thread background processing of commits.
1 parent 8f6d3d1 commit 4dea720

File tree

4 files changed

+20
-3
lines changed

4 files changed

+20
-3
lines changed

packages/shared_preferences/shared_preferences/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.4
2+
3+
* Fix a regression with simultaneous writes on Android.
4+
15
## 2.0.3
26

37
* Android: don't create additional Handler when method channel is called.

packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import java.util.Map;
2424
import java.util.Set;
2525
import java.util.concurrent.ExecutorService;
26-
import java.util.concurrent.SynchronousQueue;
26+
import java.util.concurrent.LinkedBlockingQueue;
2727
import java.util.concurrent.ThreadPoolExecutor;
2828
import java.util.concurrent.TimeUnit;
2929

@@ -53,7 +53,7 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
5353
MethodCallHandlerImpl(Context context) {
5454
preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
5555
executor =
56-
new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
56+
new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
5757
handler = new Handler(Looper.getMainLooper());
5858
}
5959

packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,18 @@ void main() {
9191
expect(preferences.getDouble('double'), null);
9292
expect(preferences.getStringList('List'), null);
9393
});
94+
95+
testWidgets('simultaneous writes', (WidgetTester _) async {
96+
final List<Future<bool>> writes = <Future<bool>>[];
97+
final int writeCount = 100;
98+
for (int i = 1; i <= writeCount; i++) {
99+
writes.add(preferences.setInt('int', i));
100+
}
101+
List<bool> result = await Future.wait(writes, eagerError: true);
102+
// All writes should succeed.
103+
expect(result.where((element) => !element), isEmpty);
104+
// The last write should win.
105+
expect(preferences.getInt('int'), writeCount);
106+
});
94107
});
95108
}

packages/shared_preferences/shared_preferences/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: shared_preferences
22
description: Flutter plugin for reading and writing simple key-value pairs.
33
Wraps NSUserDefaults on iOS and SharedPreferences on Android.
44
homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences
5-
version: 2.0.3
5+
version: 2.0.4
66

77
flutter:
88
plugin:

0 commit comments

Comments
 (0)