Flutter启动流程的深入解析

 更新时间:2019年04月15日 11:44:25   作者:caobugs  
这篇文章主要给大家介绍了关于Flutter启动流程的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Flutter具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

Flutter是怎么启动起来的,是在Android的Activity的启动之后吗?等等这样的问题,在这个文章中将被解答。

从MainActivity开始

新创建一个Flutter项目,在清单文件中默认被启动的Activity是MainActivity,而MainActivity继承的是FlutterActivity。那么问题好像简单了,我们分析一下FlutterActivity,下面是MainActivity的代码。

public class MainActivity extends FlutterActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 GeneratedPluginRegistrant.registerWith(this);
 }
}

上面的源码很简单,有两个点需要关注,第一个就是在MainActivity.onCreate()中调用了GeneratedPluginRegistrant.registerWith()这个方法,第二个是MainActivity继承自FlutterActivity,我们对这两个关注点依次进行分析。

GeneratedPluginRegistrant.registerWith()分析

我们查看GeneratedPluginRegistrant,发现这个类是Android Studio自动生成的,并且不建议修改,这个类也非常简单,下面是GeneratedPluginRegistrant的代码。

public final class GeneratedPluginRegistrant {
 public static void registerWith(PluginRegistry registry) {
 if (alreadyRegisteredWith(registry)) {
 return;
 }
 }

 private static boolean alreadyRegisteredWith(PluginRegistry registry) {
 final String key = GeneratedPluginRegistrant.class.getCanonicalName();
 if (registry.hasPlugin(key)) {
 return true;
 }
 registry.registrarFor(key);
 return false;
 }
}

如果PluginRegistry已经包含了GeneratedPluginRegistrant就直接返回true,如没有就调用PluginRegistry.registrarFor()进行注册。

我们分析一下PluginRegistry,看看是怎么注册的,发现PluginRegistry是一个接口,下面是PluginRegistry的代码。

public interface PluginRegistry {
 Registrar registrarFor(String pluginKey);
}

PluginRegistry的实现是谁呢?是FlutterActivity,下面开发分析FlutterActivity,暂时看FlutterActivity比较重要,因为这个类是MainActivity的父类,还是PluginRegistry的具体实现类。

FlutterActivity分析

下面是FlutterActivity的代码。

public class FlutterActivity extends Activity implements FlutterView.Provider, PluginRegistry, ViewFactory {
 private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
 
 private final FlutterActivityEvents eventDelegate = delegate;
 private final FlutterView.Provider viewProvider = delegate;
 private final PluginRegistry pluginRegistry = delegate;
 
 @Override
 public final boolean hasPlugin(String key) {
 return pluginRegistry.hasPlugin(key);
 }

 @Override
 public final Registrar registrarFor(String pluginKey) {
 return pluginRegistry.registrarFor(pluginKey);
 }

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 eventDelegate.onCreate(savedInstanceState);
 }

 @Override
 protected void onDestroy() {
 eventDelegate.onDestroy();
 super.onDestroy();
 }
 
 	@Override
 protected void onStop() {
 eventDelegate.onStop();
 super.onStop();
 }
 //省略了一些代码
}

从上面的代码中可以看出来,FlutterActivity是继承Activity和实现了PluginRegistry。分析一下onCreate,onStop,onDestroy这些生命周期方法被FlutterActivity.eventDelegate代理了,这个时候我们明白了,FlutterActivity就是一个空壳,真正实现是代理类FlutterActivityDelegate。

我们具体看一下,下面是FlutterActivity.onCreate()的代码。

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 eventDelegate.onCreate(savedInstanceState);
 }

FlutterActivity.$onCreate()比较简单,调用了super的onCreate()eventDelegate.onCreate() ,也就是调用了代理类的onCreate方法,下面分析FlutterActivityDelegate。

FlutterActivityDelegate分析

从上面的分析可以得出结论,FlutterActivity什么都没有做,都交个了FlutterActivityDelegate去干,这里类实现了PluginRegistry,下面是FlutterActivityDelegate的代码。

public final class FlutterActivityDelegate
 implements FlutterActivityEvents,
   FlutterView.Provider,
   PluginRegistry {
		@Override
 public void onCreate(Bundle savedInstanceState) {
 
 }   
}

还是先分析FlutterActivityDelegate.onCreate() ,这个真正干活的onCreate方法还是比较复杂的,下面是FlutterActivityDelegate.onCreate()的代码。

@Override
public void onCreate(Bundle savedInstanceState) {
 String[] args = getArgsFromIntent(activity.getIntent());//1
 FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);//2
 flutterView = viewFactory.createFlutterView(activity);//3
 if (flutterView == null) {
 FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
 flutterView = new FlutterView(activity, null, nativeView);//4
 flutterView.setLayoutParams(matchParent);
 activity.setContentView(flutterView);//5
 launchView = createLaunchView();
 if (launchView != null) {
  addLaunchView();
 }
 }
 if (loadIntent(activity.getIntent())) {
 return;
 }
 String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext());
 if (appBundlePath != null) {
 runBundle(appBundlePath);
 }
}

注释1

得到了一些参数,这些参数是干啥用的?我们拿一个trace-startup参数为例进行简单介绍下面是FlutterActivityDelegate.getArgsFromIntent()的代码。

private static String[] getArgsFromIntent(Intent intent) {
 ArrayList<String> args = new ArrayList<>();
 if (intent.getBooleanExtra("trace-startup", false)) {
 args.add("--trace-startup");
 }
 if (intent.getBooleanExtra("start-paused", false)) {
 args.add("--start-paused");
 }
 
 if (!args.isEmpty()) {
 String[] argsArray = new String[args.size()];
 return args.toArray(argsArray);
 }
 return null;
}

当你安装一个App的时候,可以用下面这个命令,

flutter run --trace-startup --profile

安装完之后会生下面这个json,

{
 "engineEnterTimestampMicros": 273508186457,
 "timeToFrameworkInitMicros": 271420,
 "timeToFirstFrameMicros": 469796,
 "timeAfterFrameworkInitMicros": 198376
}

这个json会显示进入Flutter引擎的时间和展示应用第一帧的时间等等。

注释2

调用 FlutterMain.ensureInitializationComplete() ,这方法初始化了Flutter,下面是ensureInitializationComplete的代码。

 public static void ensureInitializationComplete(Context applicationContext, String[] args) {
 if (Looper.myLooper() != Looper.getMainLooper()) {
  throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
 }
 try {
  sResourceExtractor.waitForCompletion();
  List<String> shellArgs = new ArrayList<>();
  shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
 
  String appBundlePath = findAppBundlePath(applicationContext);
  String appStoragePath = PathUtils.getFilesDir(applicationContext);
  
  nativeInit(applicationContext, shellArgs.toArray(new String[0]),
  appBundlePath, appStoragePath, engineCachesPath);//1
 } catch (Exception e) {
  Log.e(TAG, "Flutter initialization failed.", e);
  throw new RuntimeException(e);
 }
 }

		//native方法
 private static native void nativeInit(Context context, String[] args, String 				bundlePath, String appStoragePath, String engineCachesPath);

先判断是不是主线程,如果不是主线程直接抛出异常。初始化参数调用 FlutterMain.nativeInit()方法,这个方法是native方法,主要的用途是初始化Flutter。

注释3

ViewFactory是一个接口,ViewFactory.createFlutterView()的具体实现有两个,分别是FlutterActivity.createFlutterView()FlutterFragmentActivity.createFlutterView()现在这个两个具体实现都返回null,也就是一定会走到注释4。

注释4

创建FlutterView,那么FlutterView是什么呢?看一下类的声明,下面是FlutterView的声明的代码,

public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry 

}

原来是一 SurfaceView,这个就很容易理解了。

注释5

关键来了,下面是调用setContentView的代码,

 activity.setContentView(flutterView);

把FlutterView加载到Activity中,折腾了半天,就是做了这样一件事,说白了就是创建了一个FlutterView,并且把这个view显示到屏幕上。

下面是Flutter的启动流程图。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

相关文章

  • Python的异常概念介绍以及处理

    Python的异常概念介绍以及处理

    本篇文章给大家分享了关于Python异常的相关概念知识点以及处理方法,对此有需要的朋友赶快学习下吧。
    2018-03-03
  • android studio开发实现APP开机自启动

    android studio开发实现APP开机自启动

    这篇文章主要为大家详细介绍了android studio开发实现APP开机自启动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 2021最新Android笔试题总结美团Android岗职能要求

    2021最新Android笔试题总结美团Android岗职能要求

    这篇文章主要介绍了2021最新Android笔试题总结以及美团Android岗职能要求,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • Android使用Intent实现页面跳转

    Android使用Intent实现页面跳转

    这篇文章主要为大家详细介绍了Android使用Intent实现页面跳转,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • Android 连接Wifi和创建Wifi热点的实例

    Android 连接Wifi和创建Wifi热点的实例

    本篇文章介绍了Android 连接Wifi和创建Wifi热点,小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧。
    2016-10-10
  • Jenkins打包android应用时自动签名apk详解

    Jenkins打包android应用时自动签名apk详解

    这篇文章主要介绍了Jenkins打包android应用时自动签名apk详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Android多个TAB选项卡切换效果

    Android多个TAB选项卡切换效果

    这篇文章主要介绍了Android多个TAB选项卡切换效果的实现代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • Android双重SurfaceView实现弹幕效果

    Android双重SurfaceView实现弹幕效果

    这篇文章主要为大家详细介绍了Android双重SurfaceView实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-11-11
  • Android编程检测手机录音权限是否打开的方法

    Android编程检测手机录音权限是否打开的方法

    这篇文章主要介绍了Android编程检测手机录音权限是否打开的方法,涉及Android针对音频操作的相关技巧与注意事项,需要的朋友可以参考下
    2017-11-11
  • Android开启ADB网络调试方法

    Android开启ADB网络调试方法

    今天小编就为大家分享一篇Android开启ADB网络调试方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08

最新评论