赞
踩
分为两个部分,Android应用启动和Flutter启动,FlutterView显示出来才表示Flutter加载完成,从MainActivity到FlutterView显示有一个时间间隔,会出现白屏现象,Flutter框架中为了消除白屏,在创建FlutterView的同时创建了FlutterSplashView,当FlutterView第一帧加载完成,则通知将FlutterSplashView移除。
public class MainActivity extends FlutterActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public SplashScreen provideSplashScreen() {
return new SimpleSplashScreen();
}
}
首先看入口,MainActivity就只是继承了FlutterActivity,没有实现其他方法,看onCreate()方法。
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { // 切换背景为普通主题 switchLaunchThemeForNormalTheme(); super.onCreate(savedInstanceState); // 发送onCreate的通知 lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); delegate = new FlutterActivityAndFragmentDelegate(this); // 非常重要的方法 delegate.onAttach(this); delegate.onActivityCreated(savedInstanceState); configureWindowForTransparency(); setContentView(createFlutterView()); configureStatusBarForFullscreenFlutterExperience(); }
在Flutter构建的项目中src/main/res/values/styles.xml,包含LaunchTheme和NormalTheme主题,LaunchTheme作为Android启动时配置背景使用,NormalTheme则为Android应用启动后,Activity的默认主题。
比较核心的类,实际执行操作的代理类。使用一个代理类能保证FlutterActivity和FlutterFragment实现相同的逻辑。内部接口Host继承
interface Host extends SplashScreenProvider, FlutterEngineProvider, FlutterEngineConfigurator { } public interface SplashScreenProvider { @Nullable SplashScreen provideSplashScreen(); } public interface FlutterEngineProvider { @Nullable FlutterEngine provideFlutterEngine(@NonNull Context context); } public interface FlutterEngineConfigurator { void configureFlutterEngine(@NonNull FlutterEngine flutterEngine); void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine); }
这是个初始化Flutter非常核心的方法。主要有以下几个功能
void onAttach(@NonNull Context context) { // 确认是否实例还在 ensureAlive(); if (flutterEngine == null) { // 第一步 setupFlutterEngine(); } // 第二步 platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine); // 第三步 if (host.shouldAttachEngineToActivity()) { flutterEngine .getActivityControlSurface() .attachToActivity(host.getActivity(), host.getLifecycle()); } // 第四步 host.configureFlutterEngine(flutterEngine); }
void setupFlutterEngine() { // 首先 String cachedEngineId = host.getCachedEngineId(); if (cachedEngineId != null) { flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId); isFlutterEngineFromHost = true; if (flutterEngine == null) { throw new IllegalStateException( "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '" + cachedEngineId + "'"); } return; } flutterEngine = host.provideFlutterEngine(host.getContext()); if (flutterEngine != null) { isFlutterEngineFromHost = true; return; } flutterEngine = new FlutterEngine( host.getContext(), host.getFlutterShellArgs().toArray(), /*automaticallyRegisterPlugins=*/ false, /*willProvideRestorationData=*/ host.shouldRestoreAndSaveState()); isFlutterEngineFromHost = false; }
FlutterEngine构造函数简略介绍
flutterEngine =
new FlutterEngine(
host.getContext(),
host.getFlutterShellArgs().toArray(),
/*automaticallyRegisterPlugins=*/ false,
/*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());
// ...省略
// 以下是注册插件,
this.pluginRegistry =
new FlutterEnginePluginRegistry(context.getApplicationContext(), this, flutterLoader);
// 由于automaticallyRegisterPlugins为false,这里其实并没有关联插件
if (automaticallyRegisterPlugins) {
registerPlugins();
}
platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
public PlatformPlugin(Activity activity, PlatformChannel platformChannel) {
this.activity = activity;
this.platformChannel = platformChannel;
this.platformChannel.setPlatformMessageHandler(mPlatformMessageHandler);
mEnabledOverlays = DEFAULT_SYSTEM_UI;
}
提供了原生的plugin方法,通过PlatformChannel调用,如:更改状态栏、剪贴板等。
if (host.shouldAttachEngineToActivity()) {
flutterEngine
.getActivityControlSurface()
.attachToActivity(host.getActivity(), host.getLifecycle());
}
for (ActivityAware activityAware : activityAwarePlugins.values()) {
if (isWaitingForActivityReattachment) {
activityAware.onReattachedToActivityForConfigChanges(activityPluginBinding);
} else {
activityAware.onAttachedToActivity(activityPluginBinding);
}
}
如果开启了自动装配automaticallyRegisterPlugins = true,则第一步中FlutterEnginePluginRegistry.registerPlugins()注册的第三方插件,保存在了activityAwarePlugins中。FlutterEnginePluginRegistry.attachToActivity中将activityAwarePlugins方法遍历出来与Activity关联。
但其实Flutter默认实现是把automaticallyRegisterPlugins设置为false,所以这里并没有绑定操作。
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
}
注册pubspec.yaml里的原生插件,会在这里调用。
以下是我引入了网络环境判断的插件
public final class GeneratedPluginRegistrant {
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
flutterEngine.getPlugins().add(new io.flutter.plugins.connectivity.ConnectivityPlugin());
}
}
最终会调用FlutterEngin -> FlutterEnginePluginRegistry.add方法,并且将这个Flugin与Activity关联起来。
@Override
public void add(@NonNull FlutterPlugin plugin) {
plugins.put(plugin.getClass(), plugin);
plugin.onAttachedToEngine(pluginBinding);
if (plugin instanceof ActivityAware) {
ActivityAware activityAware = (ActivityAware) plugin;
activityAwarePlugins.put(plugin.getClass(), activityAware);
if (isAttachedToActivity()) {
activityAware.onAttachedToActivity(activityPluginBinding);
}
}
}
@NonNull View onCreateView( LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // 第一步 if (host.getRenderMode() == RenderMode.surface) { FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView( host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent); host.onFlutterSurfaceViewCreated(flutterSurfaceView); flutterView = new FlutterView(host.getActivity(), flutterSurfaceView); } else { FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity()); host.onFlutterTextureViewCreated(flutterTextureView); flutterView = new FlutterView(host.getActivity(), flutterTextureView); } // 第二步 flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener); // 第三步 flutterSplashView = new FlutterSplashView(host.getContext()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { flutterSplashView.setId(View.generateViewId()); flutterSplashView.setId(486947586); } flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen()); // 第四步 Log.v(TAG, "Attaching FlutterEngine to FlutterView."); flutterView.attachToFlutterEngine(flutterEngine); // 第五步 return flutterSplashView; }
Flutter提供了两种渲染模式, RenderMode.surface , RenderMode.texture,默认使用了Surface方式。
Android中TextureView与SurfaceView的区别。
当Flutter引擎、绘制工具等准备完成,并完成了FlutterView的第一帧绘制则会回调,这个回调后面就有很大用处。
这里开始就是启动页的初始化。以下是启动页的核心,后面一起讲。
由于flutterView是作为flutterSplashView的一个参数,所以flutterSplashView是持有了flutterView。
flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
此时,Flutter的框架Embedder和Engine层就关联在一起,FlutterEngine将绘制的ui反映到FlutterView上。
将flutterSplashView返回给setContentView,作为显示内容,也就是屏幕上看到的界面。
final class FlutterSplashView extends FrameLayout {
}
首先可以看到,FlutterSplashView就是一个FrameLayout。
public void displayFlutterViewWithSplash( @NonNull FlutterView flutterView, @Nullable SplashScreen splashScreen) { // 第一步 this.flutterView = flutterView; addView(flutterView); this.splashScreen = splashScreen; // 第二步 if (splashScreen != null) { if (isSplashScreenNeededNow()) { Log.v(TAG, "Showing splash screen UI."); // 第三步 splashScreenView = splashScreen.createSplashView(getContext(), splashScreenState); addView(this.splashScreenView); // 第四步 flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener); } } } splashScreen的参数,是从host.provideSplashScreen()得到的,而host其实就是FlutterActivity实现的一个接口,最终是由FlutterActivity中实现了provideSplashScreen。
前面说了,FlutterSplashView是一个FrameLayout。首先在FlutterSplashView中保存了FlutterView的引用,然后将FlutterView添加到FrameLayout中。
判断splashScreen是否为空,默认Flutter框架提供了实现View,默认是一个白屏页。
通过splashScreen.createSplashView得到splashScreenView,splashScreen的参数,是从host.provideSplashScreen()得到的,而host其实就是FlutterActivity实现的一个接口,最终是由FlutterActivity中实现了provideSplashScreen。
回调函数,onTransitionComplete其实是一个Runnable方法,内部调用了removeView(splashScreenView),将splashScreenView从上层移除,这样FlutterView就显示在出来了。
移除splashScreenView的方法也有了,只要在splashScreen.transitionToFlutter的实现方法中调用onTransitionComplete.run()就能移除splashScreenView。
private void transitionToFlutter() {
splashScreen.transitionToFlutter(onTransitionComplete);
}
private final Runnable onTransitionComplete =
new Runnable() {
@Override
public void run() {
// 关键
removeView(splashScreenView);
previousCompletedSplashIsolate = transitioningIsolateId;
}
};
也就是说,只要控制了onTransitionComplete.run()的调用时机,就能决定关闭的时机。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。