diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 5e09b3f87fb0..d51828c05e9d 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.13+3 + +* Android: replace [AsyncTask](https://developer.android.com/reference/android/os/AsyncTask) (was deprecated in API level 30) by [Executor](https://developer.android.com/reference/java/util/concurrent/Executor) + ## 0.5.13+2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/shared_preferences/shared_preferences/android/build.gradle b/packages/shared_preferences/shared_preferences/android/build.gradle index 5fc746c8e71f..92bb5fb0b850 100644 --- a/packages/shared_preferences/shared_preferences/android/build.gradle +++ b/packages/shared_preferences/shared_preferences/android/build.gradle @@ -40,3 +40,7 @@ android { disable 'InvalidPackage' } } + +dependencies { + implementation 'com.google.guava:guava:28.1-android' +} \ No newline at end of file diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java index 33f2474592fa..74545203be24 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java @@ -6,8 +6,15 @@ import android.content.Context; import android.content.SharedPreferences; -import android.os.AsyncTask; +import android.os.Handler; +import android.os.Looper; import android.util.Base64; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import java.io.ByteArrayInputStream; @@ -21,6 +28,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * Implementation of the {@link MethodChannel.MethodCallHandler} for the plugin. It is also @@ -30,6 +40,7 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { private static final String SHARED_PREFERENCES_NAME = "FlutterSharedPreferences"; + private static final String SHARED_PREFERENCES_ERROR_CODE = "shared-preferences-error"; // Fun fact: The following is a base64 encoding of the string "This is the prefix for a list." private static final String LIST_IDENTIFIER = "VGhpcyBpcyB0aGUgcHJlZml4IGZvciBhIGxpc3Qu"; @@ -37,6 +48,8 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { private static final String DOUBLE_PREFIX = "VGhpcyBpcyB0aGUgcHJlZml4IGZvciBEb3VibGUu"; private final android.content.SharedPreferences preferences; + private final ExecutorService executor; + private final Executor uiThreadExecutor; /** * Constructs a {@link MethodCallHandlerImpl} instance. Creates a {@link @@ -44,10 +57,17 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { */ MethodCallHandlerImpl(Context context) { preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); + executor = + Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder() + .setNameFormat("shared-preferences-background-%d") + .setPriority(Thread.NORM_PRIORITY) + .build()); + uiThreadExecutor = new UiThreadExecutor(); } @Override - public void onMethodCall(MethodCall call, MethodChannel.Result result) { + public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) { String key = call.argument("key"); try { switch (call.method) { @@ -118,17 +138,42 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { private void commitAsync( final SharedPreferences.Editor editor, final MethodChannel.Result result) { - new AsyncTask() { - @Override - protected Boolean doInBackground(Void... voids) { - return editor.commit(); - } + if (executor.isShutdown()) { + return; + } - @Override - protected void onPostExecute(Boolean value) { - result.success(value); - } - }.execute(); + final SettableFuture future = SettableFuture.create(); + + Futures.addCallback( + future, + new FutureCallback() { + @Override + public void onSuccess(@Nullable Boolean b) { + if (b != null) { + result.success(b); + } else { + result.error(SHARED_PREFERENCES_ERROR_CODE, "Null result", null); + } + } + + @Override + public void onFailure(@NonNull Throwable t) { + result.error(SHARED_PREFERENCES_ERROR_CODE, t.getMessage(), null); + } + }, + uiThreadExecutor); + + executor.execute( + new Runnable() { + @Override + public void run() { + try { + future.set(editor.commit()); + } catch (Throwable t) { + future.setException(t); + } + } + }); } private List decodeList(String encodedList) throws IOException { @@ -200,4 +245,17 @@ private Map getAllPrefs() throws IOException { } return filteredPrefs; } + + void teardown() { + executor.shutdown(); + } + + private static class UiThreadExecutor implements Executor { + private final Handler handler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(Runnable command) { + handler.post(command); + } + } } diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java index be627f3ce613..df5f08d9157c 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java @@ -13,6 +13,7 @@ public class SharedPreferencesPlugin implements FlutterPlugin { private static final String CHANNEL_NAME = "plugins.flutter.io/shared_preferences"; private MethodChannel channel; + private MethodCallHandlerImpl handler; @SuppressWarnings("deprecation") public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { @@ -32,11 +33,12 @@ public void onDetachedFromEngine(FlutterPlugin.FlutterPluginBinding binding) { private void setupChannel(BinaryMessenger messenger, Context context) { channel = new MethodChannel(messenger, CHANNEL_NAME); - MethodCallHandlerImpl handler = new MethodCallHandlerImpl(context); + handler = new MethodCallHandlerImpl(context); channel.setMethodCallHandler(handler); } private void teardownChannel() { + handler.teardown(); channel.setMethodCallHandler(null); channel = null; } diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 69689c738b8e..a7e147c70cab 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.13+2 +version: 0.5.13+3 flutter: plugin: