2222import io .flutter .view .VsyncWaiter ;
2323import java .io .File ;
2424import java .util .*;
25+ import java .util .concurrent .Callable ;
26+ import java .util .concurrent .Executors ;
27+ import java .util .concurrent .Future ;
2528
2629/** Finds Flutter resources in an application APK and also loads Flutter's native library. */
2730public class FlutterLoader {
@@ -76,10 +79,29 @@ public static FlutterLoader getInstance() {
7679 }
7780
7881 private boolean initialized = false ;
79- @ Nullable private ResourceExtractor resourceExtractor ;
8082 @ Nullable private Settings settings ;
8183 private long initStartTimestampMillis ;
8284
85+ private static class InitResult {
86+ final String appStoragePath ;
87+ final String engineCachesPath ;
88+ final String dataDirPath ;
89+ final ResourceExtractor resourceExtractor ;
90+
91+ private InitResult (
92+ String appStoragePath ,
93+ String engineCachesPath ,
94+ String dataDirPath ,
95+ ResourceExtractor resourceExtractor ) {
96+ this .appStoragePath = appStoragePath ;
97+ this .engineCachesPath = engineCachesPath ;
98+ this .dataDirPath = dataDirPath ;
99+ this .resourceExtractor = resourceExtractor ;
100+ }
101+ }
102+
103+ @ Nullable Future <InitResult > initResultFuture ;
104+
83105 /**
84106 * Starts initialization of the native system.
85107 *
@@ -110,18 +132,32 @@ public void startInitialization(@NonNull Context applicationContext, @NonNull Se
110132 }
111133
112134 // Ensure that the context is actually the application context.
113- applicationContext = applicationContext .getApplicationContext ();
135+ final Context appContext = applicationContext .getApplicationContext ();
114136
115137 this .settings = settings ;
116138
117139 initStartTimestampMillis = SystemClock .uptimeMillis ();
118- initResources (applicationContext );
119140
120- System .loadLibrary ("flutter" );
121-
122- VsyncWaiter .getInstance (
123- (WindowManager ) applicationContext .getSystemService (Context .WINDOW_SERVICE ))
141+ VsyncWaiter .getInstance ((WindowManager ) appContext .getSystemService (Context .WINDOW_SERVICE ))
124142 .init ();
143+
144+ // Use a background thread for initialization tasks that require disk access.
145+ Callable <InitResult > initTask =
146+ new Callable <InitResult >() {
147+ @ Override
148+ public InitResult call () {
149+ ResourceExtractor resourceExtractor = initResources (appContext );
150+
151+ System .loadLibrary ("flutter" );
152+
153+ return new InitResult (
154+ PathUtils .getFilesDir (appContext ),
155+ PathUtils .getCacheDirectory (appContext ),
156+ PathUtils .getDataDirectory (appContext ),
157+ resourceExtractor );
158+ }
159+ };
160+ initResultFuture = Executors .newSingleThreadExecutor ().submit (initTask );
125161 }
126162
127163 /**
@@ -146,8 +182,10 @@ public void ensureInitializationComplete(
146182 "ensureInitializationComplete must be called after startInitialization" );
147183 }
148184 try {
149- if (resourceExtractor != null ) {
150- resourceExtractor .waitForCompletion ();
185+ InitResult result = initResultFuture .get ();
186+
187+ if (result .resourceExtractor != null ) {
188+ result .resourceExtractor .waitForCompletion ();
151189 }
152190
153191 List <String > shellArgs = new ArrayList <>();
@@ -166,8 +204,7 @@ public void ensureInitializationComplete(
166204
167205 String kernelPath = null ;
168206 if (BuildConfig .DEBUG || BuildConfig .JIT_RELEASE ) {
169- String snapshotAssetPath =
170- PathUtils .getDataDirectory (applicationContext ) + File .separator + flutterAssetsDir ;
207+ String snapshotAssetPath = result .dataDirPath + File .separator + flutterAssetsDir ;
171208 kernelPath = snapshotAssetPath + File .separator + DEFAULT_KERNEL_BLOB ;
172209 shellArgs .add ("--" + SNAPSHOT_ASSET_PATH_KEY + "=" + snapshotAssetPath );
173210 shellArgs .add ("--" + VM_SNAPSHOT_DATA_KEY + "=" + vmSnapshotData );
@@ -187,20 +224,18 @@ public void ensureInitializationComplete(
187224 + aotSharedLibraryName );
188225 }
189226
190- shellArgs .add ("--cache-dir-path=" + PathUtils . getCacheDirectory ( applicationContext ) );
227+ shellArgs .add ("--cache-dir-path=" + result . engineCachesPath );
191228 if (settings .getLogTag () != null ) {
192229 shellArgs .add ("--log-tag=" + settings .getLogTag ());
193230 }
194231
195- String appStoragePath = PathUtils .getFilesDir (applicationContext );
196- String engineCachesPath = PathUtils .getCacheDirectory (applicationContext );
197232 long initTimeMillis = SystemClock .uptimeMillis () - initStartTimestampMillis ;
198233 FlutterJNI .nativeInit (
199234 applicationContext ,
200235 shellArgs .toArray (new String [0 ]),
201236 kernelPath ,
202- appStoragePath ,
203- engineCachesPath ,
237+ result . appStoragePath ,
238+ result . engineCachesPath ,
204239 initTimeMillis );
205240
206241 initialized = true ;
@@ -235,8 +270,15 @@ public void ensureInitializationCompleteAsync(
235270 new Runnable () {
236271 @ Override
237272 public void run () {
238- if (resourceExtractor != null ) {
239- resourceExtractor .waitForCompletion ();
273+ InitResult result ;
274+ try {
275+ result = initResultFuture .get ();
276+ } catch (Exception e ) {
277+ Log .e (TAG , "Flutter initialization failed." , e );
278+ throw new RuntimeException (e );
279+ }
280+ if (result .resourceExtractor != null ) {
281+ result .resourceExtractor .waitForCompletion ();
240282 }
241283 new Handler (Looper .getMainLooper ())
242284 .post (
@@ -288,7 +330,8 @@ private void initConfig(@NonNull Context applicationContext) {
288330 }
289331
290332 /** Extract assets out of the APK that need to be cached as uncompressed files on disk. */
291- private void initResources (@ NonNull Context applicationContext ) {
333+ private ResourceExtractor initResources (@ NonNull Context applicationContext ) {
334+ ResourceExtractor resourceExtractor = null ;
292335 if (BuildConfig .DEBUG || BuildConfig .JIT_RELEASE ) {
293336 final String dataDirPath = PathUtils .getDataDirectory (applicationContext );
294337 final String packageName = applicationContext .getPackageName ();
@@ -306,6 +349,7 @@ private void initResources(@NonNull Context applicationContext) {
306349
307350 resourceExtractor .start ();
308351 }
352+ return resourceExtractor ;
309353 }
310354
311355 @ NonNull
0 commit comments