Skip to content

Commit e555d7d

Browse files
mehmetfEgor
authored andcommitted
[path_provider_android] Move Path operations to background thread (flutter#3070)
1 parent 7f362d9 commit e555d7d

File tree

4 files changed

+67
-7
lines changed

4 files changed

+67
-7
lines changed

packages/path_provider/path_provider/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.6.19
2+
3+
* Android implementation does path queries in the background thread rather than UI thread.
4+
15
## 1.6.18
26

37
* Keep handling deprecated Android v1 classes for backward compatibility.

packages/path_provider/path_provider/android/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,16 @@ android {
3131
lintOptions {
3232
disable 'InvalidPackage'
3333
}
34+
android {
35+
compileOptions {
36+
sourceCompatibility 1.8
37+
targetCompatibility 1.8
38+
}
39+
}
3440
}
3541

3642
dependencies {
3743
implementation 'androidx.annotation:annotation:1.1.0'
44+
implementation 'com.google.guava:guava:20.0'
3845
testImplementation 'junit:junit:4.12'
3946
}

packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77
import android.content.Context;
88
import android.os.Build.VERSION;
99
import android.os.Build.VERSION_CODES;
10+
import android.os.Handler;
11+
import android.os.Looper;
1012
import androidx.annotation.NonNull;
13+
import com.google.common.util.concurrent.FutureCallback;
14+
import com.google.common.util.concurrent.Futures;
15+
import com.google.common.util.concurrent.SettableFuture;
16+
import com.google.common.util.concurrent.ThreadFactoryBuilder;
1117
import io.flutter.embedding.engine.plugins.FlutterPlugin;
1218
import io.flutter.plugin.common.MethodCall;
1319
import io.flutter.plugin.common.MethodChannel;
@@ -17,11 +23,21 @@
1723
import java.io.File;
1824
import java.util.ArrayList;
1925
import java.util.List;
26+
import java.util.concurrent.Callable;
27+
import java.util.concurrent.Executor;
28+
import java.util.concurrent.Executors;
2029

2130
public class PathProviderPlugin implements FlutterPlugin, MethodCallHandler {
2231

2332
private Context context;
2433
private MethodChannel channel;
34+
private final Executor uiThreadExecutor = new UiThreadExecutor();
35+
private final Executor executor =
36+
Executors.newSingleThreadExecutor(
37+
new ThreadFactoryBuilder()
38+
.setNameFormat("path-provider-background-%d")
39+
.setPriority(Thread.NORM_PRIORITY)
40+
.build());
2541

2642
public PathProviderPlugin() {}
2743

@@ -46,28 +62,52 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
4662
channel = null;
4763
}
4864

65+
private <T> void executeInBackground(Callable<T> task, Result result) {
66+
final SettableFuture<T> future = SettableFuture.create();
67+
Futures.addCallback(
68+
future,
69+
new FutureCallback<T>() {
70+
public void onSuccess(T answer) {
71+
result.success(answer);
72+
}
73+
74+
public void onFailure(Throwable t) {
75+
result.error(t.getClass().getName(), t.getMessage(), null);
76+
}
77+
},
78+
uiThreadExecutor);
79+
executor.execute(
80+
() -> {
81+
try {
82+
future.set(task.call());
83+
} catch (Throwable t) {
84+
future.setException(t);
85+
}
86+
});
87+
}
88+
4989
@Override
5090
public void onMethodCall(MethodCall call, @NonNull Result result) {
5191
switch (call.method) {
5292
case "getTemporaryDirectory":
53-
result.success(getPathProviderTemporaryDirectory());
93+
executeInBackground(() -> getPathProviderTemporaryDirectory(), result);
5494
break;
5595
case "getApplicationDocumentsDirectory":
56-
result.success(getPathProviderApplicationDocumentsDirectory());
96+
executeInBackground(() -> getPathProviderApplicationDocumentsDirectory(), result);
5797
break;
5898
case "getStorageDirectory":
59-
result.success(getPathProviderStorageDirectory());
99+
executeInBackground(() -> getPathProviderStorageDirectory(), result);
60100
break;
61101
case "getExternalCacheDirectories":
62-
result.success(getPathProviderExternalCacheDirectories());
102+
executeInBackground(() -> getPathProviderExternalCacheDirectories(), result);
63103
break;
64104
case "getExternalStorageDirectories":
65105
final Integer type = call.argument("type");
66106
final String directoryName = StorageDirectoryMapper.androidType(type);
67-
result.success(getPathProviderExternalStorageDirectories(directoryName));
107+
executeInBackground(() -> getPathProviderExternalStorageDirectories(directoryName), result);
68108
break;
69109
case "getApplicationSupportDirectory":
70-
result.success(getApplicationSupportDirectory());
110+
executeInBackground(() -> getApplicationSupportDirectory(), result);
71111
break;
72112
default:
73113
result.notImplemented();
@@ -131,4 +171,13 @@ private List<String> getPathProviderExternalStorageDirectories(String type) {
131171

132172
return paths;
133173
}
174+
175+
private static class UiThreadExecutor implements Executor {
176+
private final Handler handler = new Handler(Looper.getMainLooper());
177+
178+
@Override
179+
public void execute(Runnable command) {
180+
handler.post(command);
181+
}
182+
}
134183
}

packages/path_provider/path_provider/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: path_provider
22
description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.
33
homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider
4-
version: 1.6.18
4+
version: 1.6.19
55

66
flutter:
77
plugin:

0 commit comments

Comments
 (0)