From 3a11b5e8cbe6cb3b61e028447b89cde74dd355e4 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Mon, 21 Sep 2020 22:29:43 -0700 Subject: [PATCH 1/4] Move Path operations to background thread since they access disk. --- .../path_provider/path_provider/CHANGELOG.md | 4 ++ .../path_provider/android/build.gradle | 7 +++ .../pathprovider/PathProviderPlugin.java | 55 +++++++++++++++++-- 3 files changed, 60 insertions(+), 6 deletions(-) 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..a89ac8176795 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; @@ -15,6 +21,9 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.util.PathUtils; import java.io.File; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.ArrayList; import java.util.List; @@ -22,6 +31,11 @@ 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 +60,48 @@ 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 +165,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); + } + } } From bbc9c344fc9a1aeb3aa8a11e5dafc363ccba5f93 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Tue, 22 Sep 2020 11:10:28 -0700 Subject: [PATCH 2/4] formatting --- .../ios/Classes/FLTConnectivityPlugin.m | 4 +- .../pathprovider/PathProviderPlugin.java | 50 +++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m index 526bee25d561..0a65409b3828 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m @@ -156,7 +156,9 @@ - (NSString*)convertCLAuthorizationStatusToString:(CLAuthorizationStatus)status case kCLAuthorizationStatusAuthorizedWhenInUse: { return @"authorizedWhenInUse"; } - default: { return @"unknown"; } + default: { + return @"unknown"; + } } } 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 a89ac8176795..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 @@ -21,21 +21,23 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.util.PathUtils; 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; -import java.util.ArrayList; -import java.util.List; 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()); + private final Executor executor = + Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder() + .setNameFormat("path-provider-background-%d") + .setPriority(Thread.NORM_PRIORITY) + .build()); public PathProviderPlugin() {} @@ -62,22 +64,26 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { 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); - } - }); + 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 From 6a86bc75375c9ffa6615f55930d2a753b13088f9 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Tue, 22 Sep 2020 11:33:56 -0700 Subject: [PATCH 3/4] Revert conflicting files --- packages/path_provider/path_provider/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: From 1770c9f1d2fa5782bdc974b663d9ddd9ef7e10fb Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Tue, 22 Sep 2020 17:12:06 -0700 Subject: [PATCH 4/4] Revert FLTConnectivity --- .../connectivity/ios/Classes/FLTConnectivityPlugin.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m index 0a65409b3828..526bee25d561 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m @@ -156,9 +156,7 @@ - (NSString*)convertCLAuthorizationStatusToString:(CLAuthorizationStatus)status case kCLAuthorizationStatusAuthorizedWhenInUse: { return @"authorizedWhenInUse"; } - default: { - return @"unknown"; - } + default: { return @"unknown"; } } }