flutter框架:关于Flutter初始化流程
1. 引言最近在做性能优化的时候发现,在混合栈开发中,第一次启动Flutter页面的耗时总会是第二次启动Flutter页面耗时的两倍左右,这样给人感觉很不好。分析发现第一次启动Flutter页面会做一些初始化工作,借此,我梳理了下Flutter的初始化流程。 2. Flutter初始化时序Flutter初始化主要分四部分,FlutterMain初始化、FlutterNativeView初始化、FlutterView初始化和Flutter Bundle初始化。
3. 具体分析3.1 FlutterMain初始化这部分初始化工作是由Application.onCreate方法中调用开始的,在Application创建的时候就会初始化完成,不会影响Flutter页面的第一次启动,所以这里只是做一个简单分析。 public static void startInitialization(Context applicationContext, Settings settings) { // other codes ... initConfig(applicationContext); initAot(applicationContext); initResources(applicationContext); System.loadLibrary("flutter"); // other codes ...} 3.2 FlutterNativeView初始化先用一个图来展现FlutterNativeView构造函数的调用栈:
从上图的调用栈中我们知道FlutterNativeView的初始化主要做了些什么,我们再从源码角度较为深入的了解下: static const JNINativeMethod native_view_methods[] = { { .name = "nativeAttach", .signature = "(Lio/flutter/view/FlutterNativeView;)J", .fnPtr = reinterpret_cast<void*>(&shell::Attach), }, // other codes ...}; 从代码中很容易看出FlutterNativeView.attach方法最终调用了shell::Attach方法,而shell::Attach方法主要做了两件事: static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) { auto view = new PlatformViewAndroid(); // other codes ... view->Attach(); // other codes ...} 那我们再分析下PlatformViewAndroid的构造函数和Attach方法都做了些什么呢? PlatformViewAndroid::PlatformViewAndroid() : PlatformView(std::make_unique<NullRasterizer>()), android_surface_(InitializePlatformSurface()) {} void PlatformViewAndroid::Attach() { CreateEngine(); // Eagerly setup the IO thread context. We have already setup the surface. SetupResourceContextOnIOThread(); UpdateThreadPriorities(); } 其中: 3.3 FlutterView初始化FlutterView的初始化就是纯粹的Android层啦,所以相对比较简单。分析FlutterView.java的构造函数就会发现,整个FlutterView的初始化在确保FlutterNativeView的创建成功和一些必要的view设置之外,主要做了两件事:
3.4 Flutter Bundle初始化Flutter Bundle的初始化是由调用FlutterActivityDelegate.runFlutterBundle开始的,先用一张图来说明下runFlutterBundle方法的调用栈:
我们再从源码角度较为深入了解下: public void runFlutterBundle(){ // other codes ... String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext()); if (appBundlePath != null) { flutterView.runFromBundle(appBundlePath, null, "main", reuseIsolate); } } 很明显,这个runFlutterBundle并没有做太多事情,而且直接调用了FlutterView.runFromBundle方法。而后兜兜转转最后会调用到PlatformViewAndroid::RunBundleAndSnapshot方法。 void PlatformViewAndroid::RunBundleAndSnapshot(JNIEnv* env, std::string bundle_path, std::string snapshot_override, std::string entrypoint, bool reuse_runtime_controller, jobject assetManager) { // other codes ... blink::Threads::UI()->PostTask( [engine = engine_->GetWeakPtr(), asset_provider = std::move(asset_provider), bundle_path = std::move(bundle_path), entrypoint = std::move(entrypoint), reuse_runtime_controller = reuse_runtime_controller] { if (engine) engine->RunBundleWithAssets( std::move(asset_provider), std::move(bundle_path), std::move(entrypoint), reuse_runtime_controller); }); } PlatformViewAndroid::RunBundleAndSnapshot在UI线程中调用Engine::RunBundleWithAssets,最终调用Engine::DoRunBundle。 bool DartController::SendStartMessage(Dart_Handle root_library, const std::string& entrypoint) { // other codes ... // Get the closure of main(). Dart_Handle main_closure = Dart_GetClosure( root_library, Dart_NewStringFromCString(entrypoint.c_str())); // other codes ... // Grab the 'dart:isolate' library. Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate")); DART_CHECK_VALID(isolate_lib); // Send the start message containing the entry point by calling // _startMainIsolate in dart:isolate. const intptr_t kNumIsolateArgs = 2; Dart_Handle isolate_args[kNumIsolateArgs]; isolate_args[0] = main_closure; isolate_args[1] = Dart_Null(); Dart_Handle result = Dart_Invoke(isolate_lib, ToDart("_startMainIsolate"), kNumIsolateArgs, isolate_args); return LogIfError(result); } 而SendStartMessage方法主要做了三件事: 4. 总结一下本次主要分析了下FlutterActivity的onCreate方法中的Flutter初始化部分逻辑,很明显会发现主要耗时在FlutterNativeView、FlutterView和Flutter Bundle的初始化这三块,将这三部分的初始化工作前置就可以比较容易的解决引言中提出的问题。经测试发现,这样改动之后,Flutter页面第一次启动时长和后面几次启动时长差不多一样了。 作者:闲鱼技术 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |