diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index f2835c62ec6f..fe92462627df 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.19 + +* Android implementation does path queries in the background thread rather than UI thread. + ## 1.6.18 * Keep handling deprecated Android v1 classes for backward compatibility. diff --git a/packages/path_provider/path_provider/android/build.gradle b/packages/path_provider/path_provider/android/build.gradle index 93460e761568..91bedf7f29a3 100644 --- a/packages/path_provider/path_provider/android/build.gradle +++ b/packages/path_provider/path_provider/android/build.gradle @@ -31,9 +31,16 @@ android { lintOptions { disable 'InvalidPackage' } + android { + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + } } dependencies { implementation 'androidx.annotation:annotation:1.1.0' + implementation 'com.google.guava:guava:20.0' testImplementation 'junit:junit:4.12' } diff --git a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java index d091d549b68e..9a0c76232fb3 100644 --- a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java +++ b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java @@ -7,7 +7,13 @@ import android.content.Context; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import android.os.Handler; +import android.os.Looper; import androidx.annotation.NonNull; +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.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -17,11 +23,21 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; public class PathProviderPlugin implements FlutterPlugin, MethodCallHandler { private Context context; private MethodChannel channel; + private final Executor uiThreadExecutor = new UiThreadExecutor(); + private final Executor executor = + Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder() + .setNameFormat("path-provider-background-%d") + .setPriority(Thread.NORM_PRIORITY) + .build()); public PathProviderPlugin() {} @@ -46,28 +62,52 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { channel = null; } + private void executeInBackground(Callable task, Result result) { + final SettableFuture future = SettableFuture.create(); + Futures.addCallback( + future, + new FutureCallback() { + public void onSuccess(T answer) { + result.success(answer); + } + + public void onFailure(Throwable t) { + result.error(t.getClass().getName(), t.getMessage(), null); + } + }, + uiThreadExecutor); + executor.execute( + () -> { + try { + future.set(task.call()); + } catch (Throwable t) { + future.setException(t); + } + }); + } + @Override public void onMethodCall(MethodCall call, @NonNull Result result) { switch (call.method) { case "getTemporaryDirectory": - result.success(getPathProviderTemporaryDirectory()); + executeInBackground(() -> getPathProviderTemporaryDirectory(), result); break; case "getApplicationDocumentsDirectory": - result.success(getPathProviderApplicationDocumentsDirectory()); + executeInBackground(() -> getPathProviderApplicationDocumentsDirectory(), result); break; case "getStorageDirectory": - result.success(getPathProviderStorageDirectory()); + executeInBackground(() -> getPathProviderStorageDirectory(), result); break; case "getExternalCacheDirectories": - result.success(getPathProviderExternalCacheDirectories()); + executeInBackground(() -> getPathProviderExternalCacheDirectories(), result); break; case "getExternalStorageDirectories": final Integer type = call.argument("type"); final String directoryName = StorageDirectoryMapper.androidType(type); - result.success(getPathProviderExternalStorageDirectories(directoryName)); + executeInBackground(() -> getPathProviderExternalStorageDirectories(directoryName), result); break; case "getApplicationSupportDirectory": - result.success(getApplicationSupportDirectory()); + executeInBackground(() -> getApplicationSupportDirectory(), result); break; default: result.notImplemented(); @@ -131,4 +171,13 @@ private List getPathProviderExternalStorageDirectories(String type) { return paths; } + + 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/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index ec8fd855df54..0eadc40637b0 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.18 +version: 1.6.19 flutter: plugin: