Flutter小知识--从桌面启动到展示FlutterUI都发生了什么

从点击桌面icon,到展示flutter第一帧,中间还有个展示页面,这中间发生了什么?
本文基于flutter-android平台进行分析,先放一张启动效果镇楼:

splash.gif

创建一个分析demo

首先启动AndroidStudio , File-> New -> New Flutter Project -> New Flutter Application,
然后输入项目名hello_flutter, 点击next,输入你的包名,然后点击finish,样例程序创建完成。
默认文件结构如下:

hello_flutter
    -.ides
    -android
        -app/src/main
        -gradle
    -ios
    -lib
    -test
    -pubspec.yaml

点击icon启动效果大致于镇楼图类似,下面我们基于启动代码进行分析。

AndroidManifest.xml

基于之前的知识,Flutter在android平台上运行时,会生成一个FlutterView并添加到Activity的容器view中。
既然是基于android平台,那么启动入口肯定在AndroidManifest.xml中配置。


    
         //我是注释1
        
        
            
            
        
    

根据注释1 可以修改启动页展示的图片,本文不详述,后面会再写一篇关于 flutter启动页相关的内容。 由上面配置已知MainActivity是我们的启动入口,那么接下来一起看下。

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

继承了FlutterActivity,看下 继承了FlutterActivity的 onCreate 做了什么:

public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory {
    private static final String TAG = "FlutterActivity";
    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
    private final FlutterActivityEvents eventDelegate;
    private final Provider viewProvider;
    private final PluginRegistry pluginRegistry;

    public FlutterActivity() {
        this.eventDelegate = this.delegate;
        this.viewProvider = this.delegate;
        this.pluginRegistry = this.delegate;
    }

    ...

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.eventDelegate.onCreate(savedInstanceState);//注释2
    }

    ...
}

注释2 eventDelegate其实就是FlutterActivityDelegate , 它的onCreate源码如下:

public void onCreate(Bundle savedInstanceState) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Window window = activity.getWindow();
        window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        window.setStatusBarColor(0x40000000);
        window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
    }

    String[] args = getArgsFromIntent(this.activity.getIntent());
    FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
    this.flutterView = this.viewFactory.createFlutterView(this.activity);
    if (this.flutterView == null) {
        //实现了 BinaryMessenger接口,可以用于flutter与native双向通信
        FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
        //创建flutterview,并添加到activity当中
        this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
        this.flutterView.setLayoutParams(matchParent);
        this.activity.setContentView(this.flutterView);
        this.launchView = this.createLaunchView();//创建一个LaunchView,这里是我们这次启动流程的重点
        if (this.launchView != null) {
            this.addLaunchView();//添加LaunchView()
        }
    }

    if (!this.loadIntent(this.activity.getIntent())) {
        String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
        if (appBundlePath != null) {
            this.runBundle(appBundlePath);
        }

    }
}

private View createLaunchView() {
    if (!this.showSplashScreenUntilFirstFrame()) {
        return null;
    } else {
        //根据activity配置的theme中的windowBackground来生成drawable,并设置给view。这里篇幅有限,就不展开了。
        Drawable launchScreenDrawable = this.getLaunchScreenDrawableFromActivityTheme();
        if (launchScreenDrawable == null) {
            return null;
        } else {
            View view = new View(this.activity);
            view.setLayoutParams(matchParent);
            view.setBackground(launchScreenDrawable);
            return view;
        }
    }
}

private void addLaunchView() {
    if (this.launchView != null) {
        //给activity设置一个额外的content view,它添加到已经存在的view之后,已存在的对象上面的flutterview。
        this.activity.addContentView(this.launchView, matchParent);
        //给flutterview设置回调,当第一帧要显示时先动画淡出LaunchView,然后将其移除掉。
        this.flutterView.addFirstFrameListener(new FirstFrameListener() {
            public void onFirstFrame() {
                FlutterActivityDelegate.this.launchView.animate().alpha(0.0F).setListener(new AnimatorListenerAdapter() {
                    public void onAnimationEnd(Animator animation) {
                        ((ViewGroup)FlutterActivityDelegate.this.launchView.getParent()).removeView(FlutterActivityDelegate.this.launchView);
                        FlutterActivityDelegate.this.launchView = null;
                    }
                });
                FlutterActivityDelegate.this.flutterView.removeFirstFrameListener(this);
            }
        });
        this.activity.setTheme(android.R.style.Theme_Black_NoTitleBar);
    }
}

/*
 * 这里对应AndroidMenifest中的配置,如果设置是true,就希望在显示flutter第一帧之前展示一个启动页。
 */
private Boolean showSplashScreenUntilFirstFrame() {
    try {
        ActivityInfo activityInfo = this.activity.getPackageManager().getActivityInfo(this.activity.getComponentName(), 129);
        Bundle metadata = activityInfo.metaData;
        return metadata != null && metadata.getBoolean("io.flutter.app.android.SplashScreenUntilFirstFrame");
    } catch (NameNotFoundException var3) {
        return false;
    }
}

注释的比较清楚,大致流程相信看完注释就已经了解了。
总结 : 点击Icon启动 -> MainActivity.onCreate -> FlutterActivity.onCreate -> FlutterActivityDelegate.onCreate -> 创建并添加FlutterView ->
额外添加LauncherView -> FlutterView设置监听,将要展示第一帧时候移除 LauncherView。-> 展示FlutterView

后续会再补一份关于flutter splashpage相关的文章,敬请期待。


如果你觉得这篇文章对你有益,还请帮忙转发和点赞,万分感谢。

Flutter小知识--从桌面启动到展示FlutterUI都发生了什么_第1张图片
Flutter烂笔头

你可能感兴趣的:(Flutter小知识--从桌面启动到展示FlutterUI都发生了什么)