目录介绍
- 01.Android承载flutter容器
- 02.过期的NA跳转flutter计划
- 03.降级版本NA跳转Flutter解决
- 04.如何解决NA跳转flutter传参
- 05.思考遇到的几个问题剖析
- 06.Flutter页面敞开时Crash
- 07.Android引入flutter实质
- 08.Flutter启动加载流程和优化
00.举荐
- fluter Utils 工具类库:https://github.com/yangchong2…
- flutter 混合我的项目代码案例:https://github.com/yangchong2…
01.Android承载flutter容器
-
Android中如何承载flutter页面呢
- 第一种状况:从Android中弄一个容器,关上一个新的页面,装载一个新的flutter页面。
- 第二种状况:从Android中弄一个容器,在NA的页面中,装载一个flutter页面。【一个页面,有一部分是NA,有一部分是Flutter】
-
如何将Flutter编写的页面嵌入到Activity中
- 官网提供了两种形式:通过FlutterView和FlutterFragment。
02.过期的NA跳转flutter计划
2.1 应用FlutterView
-
NA增加FlutterView
- 在NA创立一个Activity,在onCreate中创立FlutterView而后增加到布局中。
- Flutter.createView()办法返回的是一个FlutterView,它继承自View,咱们能够把它当做一个一般的View。
-
Flutter.createView()办法的第三个参数传入了”yc_route”字符串,示意路由名称,它确定了Flutter中要显示的Widget。
private void addFlutterView() { // 通过FlutterView引入Flutter编写的页面 // Flutter.createView()办法返回的是一个FlutterView,它继承自View,咱们能够把它当做一个一般的View // Flutter.createView()办法的第三个参数传入了"yc_route"字符串,示意路由名称,它确定了Flutter中要显示的Widget flutterView = Flutter.createView(this, getLifecycle(), INIT_ROUTE); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); //增加到布局中 frameLayout.addView(flutterView, layoutParams); //addContentView(flutterView, layout); }
-
Flutter增加页面
- 在runApp()办法中通过window.defaultRouteName能够获取到在Flutter.createView()办法中传入的路由名称,即”yc_route”,
-
之后编写了一个_widgetForRoute()办法,依据传入的route字符串显示相应的Widget。
import 'dart:ui'; import 'package:flutter/material.dart'; void main() => runApp(_widgetForRoute(window.defaultRouteName)); Widget _widgetForRoute(String route) { switch (route) { case 'yc_route': return MyHomePage(title: '匹配到了,这个是flutter页面'); } }
-
跳转flutter所在activity黑屏
- debug包这种状况比拟显著,然而release加载很快,能够在进入Flutter页面的时候提供一个加载loading
2.2 应用FlutterFragment
-
NA增加FlutterView
- 在NA创立一个Activity,在onCreate中创立FlutterFragment而后增加到布局中。
-
Flutter.createFragment()办法传入的参数同样示意路由名称,用于确定Flutter要显示的Widget,返回一个FlutterFragment,该类继承自Fragment,将该Fragment增加到Activity中就能够了。
private void addFlutterFragment(){ // 通过FlutterFragment引入Flutter编写的页面 FragmentTransaction tx = getSupportFragmentManager().beginTransaction(); // Flutter.createFragment()办法传入的参数同样示意路由名称,用于确定Flutter要显示的Widget // 返回一个FlutterFragment,该类继承自Fragment,将该Fragment增加到Activity中就能够了。 FlutterFragment flutterFragment = Flutter.createFragment(INIT_ROUTE); tx.replace(R.id.rl_flutter, flutterFragment); tx.commit(); }
- Flutter增加页面,这个同上
2.3 须要留神的问题
-
Flutter版本升级兼容问题
- 因为Flutter版本的更新,下面介绍的内容中存在一些API曾经被废除的状况。简略查了一下理解到这个谬误是Flutter 1.12版本废除了io.flutter.facade包导致的,Flutter.createView和Flutter.createFragment这两个api找不到,固当初曾经不应用呢……
-
NA跳转flutter如何增加参数
- NA,这个传递参数只须要在路由前面拼接参数即可。
- Flutter,这个接管参数只须要解析参数即可。
- 上面降级版本FlutterView的应用案例中会说到,能够接着往下看……
03.降级版本NA跳转Flutter解决
3.1 应用新版本FlutterView
-
新版本简略阐明
- 通过FlutterView引入Flutter页面,以前咱们是通过io.flutter.facade包中Flutter类的createView()办法创立出一个FlutterView,而后增加到Activity的布局中,然而因为io.flutter.facade包的废除,该办法曾经无奈应用。
- 官网的文档有阐明目前不提供在View级别引入Flutter的便捷API,因而如果可能的话,咱们应该防止应用FlutterView,然而通过FlutterView引入Flutter页面也是可行的。
- 须要留神,这里的FlutterView位于io.flutter.embedding.android包中,和此前咱们所创立的FlutterView(位于io.flutter.view包中)是不一样的。
-
NA增加FlutterView
- 在NA创立一个Activity,在onCreate中创立FlutterView而后增加到布局中。
-
调用FlutterView的attachToFlutterEngine()办法,这个办法的作用就是将Flutter编写的UI页面显示到FlutterView中,留神到这里传入了一个flutterEngine参数,它又是什么呢?flutterEngine的类型为FlutterEngine,字面意思就是Flutter引擎,它负责在Android端执行Dart代码,将Flutter编写的UI显示到FlutterView的容器中。
private void addFlutterView() { flutterEngine = new FlutterEngine(this); binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger(); flutterEngine.getNavigationChannel().setInitialRoute("yc"); flutterEngine.getDartExecutor().executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ); // 通过FlutterView引入Flutter编写的页面 // 这里的FlutterView位于io.flutter.embedding.android包中 // 和此前咱们所创立的FlutterView(位于io.flutter.view包中)是不一样的。 // 通过查看FlutterView的源码能够发现它继承自FrameLayout,因而像一个一般的View那样增加就能够了。 flutterView = new FlutterView(this); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rlFlutter.addView(flutterView, lp); //flutterEngine.getNavigationChannel().setInitialRoute("yc"); // 要害代码,将Flutter页面显示到FlutterView中 // 这个办法的作用就是将Flutter编写的UI页面显示到FlutterView中 // flutterEngine的类型为FlutterEngine,字面意思就是Flutter引擎 // 它负责在Android端执行Dart代码,将Flutter编写的UI显示到FlutterView/FlutterActivity/FlutterFragment中。 flutterView.attachToFlutterEngine(flutterEngine); // FlutterEngine加载的路由名称为"/",咱们能够通过上面的代码指定初始路由名称 // 传参的状况没有变动,间接在路由名称前面拼接参数就能够 // todo 放在这里不失效,思考为什么 // flutterEngine.getNavigationChannel().setInitialRoute("yc"); }
-
Flutter增加页面
- 在runApp()办法中通过window.defaultRouteName能够获取到在Flutter.createView()办法中传入的路由名称,即”yc_route”,
-
之后编写了一个_widgetForRoute()办法,依据传入的route字符串显示相应的Widget。
import 'dart:ui'; import 'package:flutter/material.dart'; void main() => runApp(_widgetForRoute(window.defaultRouteName)); Widget _widgetForRoute(String route) { switch (route) { case 'yc_route': return MyHomePage(title: '匹配到了,这个是flutter页面'); } }
3.2 应用新版本FlutterFragment
-
NA有几种增加形式
-
FlutterFragment.createDefault()
- 通过FlutterFragment.createDefault()创立出FlutterFragment,创立出的Fragment显示的路由名称为”/”,如果咱们须要指定其余路由名称就不能应用这个办法了。
-
FlutterFragment.withNewEngine()
- 通过FlutterFragment.withNewEngine()获取到NewEngineFragmentBuilder对象,应用建造者模式结构出FlutterFragment对象,能够通过initialRoute()办法指定初始路由名称。
- 应用的withNewEngine()办法从名称上也能看出每次都是创立一个新的FlutterEngine对象来显示Flutter UI,然而从官网文档中能够理解到每个FlutterEngine对象在显示出Flutter UI之前是须要一个warm-up(简略了解为预热)期的,这会导致屏幕出现短暂的空白,解决形式就是事后创立并启动FlutterEngine,实现warm-up过程,而后将这个FlutterEngine缓存起来,之后应用这个FlutterEngine来显示出Flutter UI。
-
FlutterFragment.withCachedEngine
- 执行的FlutterEngineCache.getInstance().put(“my_engine_id”, flutterEngine)就是将FlutterEngine缓存起来,这里传入的”my_engine_id”就相当于缓存名称。
- 之后调用FlutterFragment.withCachedEngine(“my_engine_id”).build();获取缓存的FlutterFragment对象
-
-
NA增加FlutterFragment
- 在NA创立一个Activity,在onCreate中创立FlutterFragment而后增加到布局中。
-
Flutter.createFragment()办法传入的参数同样示意路由名称,用于确定Flutter要显示的Widget,返回一个FlutterFragment,该类继承自Fragment,将该Fragment增加到Activity中就能够了。
private void addFlutterView() { // 通过FlutterFragment引入Flutter编写的页面 // 通过FlutterFragment.createDefault()创立出FlutterFragment // 须要留神这里的FlutterFragment位于io.flutter.embedding.android包中 //FlutterFragment flutterFragment = FlutterFragment.createDefault(); // 通过FlutterFragment.withNewEngine()获取到NewEngineFragmentBuilder对象 FlutterFragment.NewEngineFragmentBuilder fragmentBuilder = FlutterFragment.withNewEngine(); // 应用建造者模式结构出FlutterFragment对象,能够通过initialRoute()办法指定初始路由名称。 // 传递参数只须要在路由名称前面进行拼接。 FlutterFragment.NewEngineFragmentBuilder initialRoute = fragmentBuilder.initialRoute("yc"); FlutterFragment flutterFragment = initialRoute.build(); getSupportFragmentManager() .beginTransaction() .add(R.id.rl_flutter, flutterFragment) .commit(); // 存在的问题 // 应用的withNewEngine()办法从名称上也能看出每次都是创立一个新的FlutterEngine对象来显示Flutter UI, // 然而从官网文档中咱们能够理解到每个FlutterEngine对象在显示出Flutter UI之前 // 是须要一个warm-up(不晓得能不能翻译为预热)期的,这会导致屏幕出现短暂的空白, // 解决形式就是事后创立并启动FlutterEngine,实现warm-up过程,而后将这个FlutterEngine缓存起来, // 之后应用这个FlutterEngine来显示出Flutter UI。 // 解决方案看:FlutterFragmentCachedActivity // 如何获取到FlutterEngine对象呢?FlutterFragment中定义了一个getFlutterEngine()办法, // 从办法名来看大略就是获取FlutterEngine对象。 // 尝试过创立MethodChannel时传入flutterFragment.getFlutterEngine().getDartExecutor(), // 运行后会间接抛出空指针异样,异样产生的地位在FlutterFragment的getFlutterEngine()办法中 // 谬误起因是这里的delegate为null,全局搜寻一下,发现在FlutterFragment的onAttach()办法中会对delegate赋值,也就是说明此时没有执行onAttach()办法。 // 猜想这就是因为下面提到过的FlutterEngine的warm-up机制,这是一个耗时过程, // 因而FlutterFragment并不会立即执行onAttach()办法,导致咱们在Activity的onCreate()办法中间接应用FlutterFragment的getFlutterEngine()办法会抛出异样。 // todo 调用上面这句话会空指针解体 // FlutterEngine flutterEngine = flutterFragment.getFlutterEngine(); }
-
Flutter增加页面
- 这个同上
3.3 应用新版本FlutterActivity
-
原生引入Flutter页面形式
- 应用FlutterActivity,这里的FlutterActivity也是位于io.flutter.embedding.android包下的。
-
首先在清单文件增加代码
<activity android:name="io.flutter.embedding.android.FlutterActivity" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:theme="@style/AppTheme" android:windowSoftInputMode="adjustResize" />
-
间接启动这个Activity,代码如下所示
/** * 和介绍的创立FlutterFragment的三种形式是对应的 * * FlutterActivity显示的Flutter路由是在创立Intent对象时指定的, * 长处就是应用起来更简略,毛病就是不够灵便, * 无奈像FlutterView/FlutterFragment那样只是作为原生页面中的一部分展现, * 因而这种形式更适宜整个页面都是由Flutter编写的场景。 */ private void test(){ // 形式一、FlutterActivity显示的路由名称为"/",不可设置 /*startActivity( FlutterActivity.createDefaultIntent(this) );*/ // 形式二、FlutterActivity显示的路由名称可设置,每次都创立一个新的FlutterEngine对象 startActivity( FlutterActivity .withNewEngine() .initialRoute("yc") .build(this) ); // 形式三、FlutterActivity显示的路由名称可设置,应用缓存好的FlutterEngine对象 /*startActivity( FlutterActivity .withCachedEngine("my_engine_id") .build(this) );*/ }
-
应用这种形式特点
- 这种形式不须要咱们本人创立一个Activity,FlutterActivity显示的Flutter路由是在创立Intent对象时指定的,长处就是应用起来更简略,毛病就是不够灵便,无奈像FlutterView/FlutterFragment那样只是作为原生页面中的一部分展现,因而这种形式更适宜整个页面都是由Flutter编写的场景。
3.4 补充阐明问题
-
将Flutter版本更新到了1.17,发现上述代码运行后FlutterView无奈显示,这个是为什么呢?
-
和官网提供的示例flutter_view进行了比照,才发现短少了上面的代码:
@Override protected void onResume() { super.onResume(); // flutterEngine.getLifecycleChannel()获取到的是一个LifecycleChannel对象,类比于MethodChannel, // 作用大略就是将Flutter和原生端的生命周期互相分割起来。 flutterEngine.getLifecycleChannel().appIsResumed(); } @Override protected void onPause() { super.onPause(); flutterEngine.getLifecycleChannel().appIsInactive(); } @Override protected void onStop() { super.onStop(); flutterEngine.getLifecycleChannel().appIsPaused(); }
-
-
可能和生命周期有关系
- flutterEngine.getLifecycleChannel()获取到的是一个LifecycleChannel对象,类比于MethodChannel,作用大略就是将Flutter和原生端的生命周期互相分割起来。
- 这里别离在onResume()、onPause()和onStop()办法中调用了LifecycleChannel的appIsResumed()、appIsInactive()和appIsPaused()办法,作用就是同步Flutter端与原生端的生命周期。增加上述代码后,FlutterView就能够失常显示了。
-
为何在之后版本要增加
- 可能是FlutterVIew的渲染机制有了一些变动,在接管到原生端对应生命周期办法中发送的告诉才会显示,具体原理还是要比照一下当初和以前的源码。
04.如何解决NA跳转flutter传参
4.1 NA如何传递参数给Flutter?
- 如果须要在页面跳转时传递参数呢,如何在Flutter代码中获取到原生代码中的参数呢?其实很简略,只须要在route前面拼接上参数就能够了。
-
以创立FlutterView的形式为例。
NavigationChannel navigationChannel = flutterEngine.getNavigationChannel(); String route = "yc?{\"name\":\"杨充\"}"; navigationChannel.setInitialRoute(route);
-
以创立FlutterFragment的形式为例
FlutterFragment.NewEngineFragmentBuilder fragmentBuilder = FlutterFragment.withNewEngine(); // 应用建造者模式结构出FlutterFragment对象,能够通过initialRoute()办法指定初始路由名称。 // 传递参数只须要在路由名称前面进行拼接。 String route = "yc?{\"author\":\"杨充\"}"; FlutterFragment.NewEngineFragmentBuilder initialRoute = fragmentBuilder.initialRoute(route); FlutterFragment flutterFragment = initialRoute.build();
4.2 传递参数注意事项
- 将路由名称和参数间用“?”隔开,就像浏览器中的url一样,参数应用了Json格局传递,起因就是不便Flutter端解析,而且对于一些简单的数据,比方自定义对象,应用Json序列化也很好实现。
4.3 Flutter接管传递参数
-
这时候Flutter端通过window.defaultRouteName获取到的就是路由名称+参数了,咱们须要将路由名称和参数离开,这就只是单纯的字符串解决。
Widget _widgetForRoute() { //var route = window.defaultRouteName; Map<String, dynamic> router = parseRouter(); var route = router["route"]; switch (route) { case 'yc': return AboutMePage(title: '匹配到了,这个是flutter页面',params : router); } } Map<String, dynamic> parseRouter(){ String url = window.defaultRouteName; // route名称,路由path门路名称 String route = url.indexOf('?') == -1 ? url : url.substring(0, url.indexOf('?')); // 参数Json字符串 String paramsJson = url.indexOf('?') == -1 ? '{}' : url.substring(url.indexOf('?') + 1); // 解析参数 Map<String, dynamic> params = json.decode(paramsJson); params["route"] = route; return params; }
- 通过”?”将路由名称和参数离开,将参数对应的Json字符串解析为Map对象,须要导入dart:convert包。
05.思考遇到的几个问题剖析
5.1 setInitialRoute失效问题
-
flutterEngine.getNavigationChannel().setInitialRoute(“yc”)失效问题
//第一种是失效的 private void addFlutterView() { flutterEngine = new FlutterEngine(this); binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger(); flutterEngine.getNavigationChannel().setInitialRoute("yc"); flutterEngine.getDartExecutor().executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ); flutterView = new FlutterView(this); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rlFlutter.addView(flutterView, lp); flutterView.attachToFlutterEngine(flutterEngine); } //第二种是不失效的 private void addFlutterView() { flutterEngine = new FlutterEngine(this); binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger(); flutterEngine.getDartExecutor().executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ); flutterView = new FlutterView(this); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rlFlutter.addView(flutterView, lp); // todo 放在这里不失效,思考为什么 flutterEngine.getNavigationChannel().setInitialRoute("yc"); flutterView.attachToFlutterEngine(flutterEngine); // todo 放在这里不失效,思考为什么 // flutterEngine.getNavigationChannel().setInitialRoute("yc"); }
5.2 flutterFragment.getFlutterEngine()空指针
-
应用场景剖析
private void createChannel() { // todo 调用上面这句话会空指针解体 FlutterEngine flutterEngine = flutterFragment.getFlutterEngine(); BinaryMessenger binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger(); nativeChannel = new MethodChannel(binaryMessenger, METHOD_CHANNEL, StandardMethodCodec.INSTANCE); } //源码 @Nullable public FlutterEngine getFlutterEngine() { return delegate.getFlutterEngine(); }
-
谬误起因是这里的delegate为null
- 翻看了一下源码,发现在FlutterFragment的onAttach()办法中会对delegate赋值,也就是说明此时没有执行onAttach()办法。
-
问题剖析
- FlutterEngine的warm-up机制,这是一个耗时过程,因而FlutterFragment并不会立即执行onAttach()办法,导致咱们在Activity的onCreate()办法中间接应用FlutterFragment的getFlutterEngine()办法会抛出异样。
-
如何解决问题
- 想要解决问题,那就要等到FlutterFragment执行完onAttach()办法在调用getFlutterEngine。那么怎么去监听这个办法执行完呢?
06.Flutter页面敞开时Crash
-
报错日志如下所示
Caused by: java.lang.RuntimeException: Cannot execute operation because FlutterJNI is not attached to native. at io.flutter.embedding.engine.FlutterJNI.ensureAttachedToNative(FlutterJNI.java:259) at io.flutter.embedding.engine.FlutterJNI.onSurfaceDestroyed(FlutterJNI.java:369) at io.flutter.embedding.engine.renderer.FlutterRenderer.stopRenderingToSurface(FlutterRenderer.java:219) at io.flutter.embedding.android.FlutterTextureView.disconnectSurfaceFromRenderer(FlutterTextureView.java:223) at io.flutter.embedding.android.FlutterTextureView.access$400(FlutterTextureView.java:33) at io.flutter.embedding.android.FlutterTextureView$1.onSurfaceTextureDestroyed(FlutterTextureView.java:84) at android.view.TextureView.releaseSurfaceTexture(TextureView.java:261) at android.view.TextureView.onDetachedFromWindowInternal(TextureView.java:232) at android.view.View.dispatchDetachedFromWindow(View.java:22072) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:4747) at android.view.ViewGroup.removeAllViewsInLayout(ViewGroup.java:6606) at android.view.ViewGroup.removeAllViews(ViewGroup.java:6552) at com.yc.fluttercontainer.FlutterEngineActivity.onDestroy(FlutterEngineActivity.java:292)
-
报错的代码如下所示
@Override protected void onDestroy() { super.onDestroy(); if (flutterEngine != null) { flutterEngine.destroy(); } mFlutterContainer.removeAllViews(); mFlutterView.removeAllViews(); if (mRenderSurface != null) { // 打断内存透露 ((FixFlutterTextureView) mRenderSurface).setSurfaceTextureListener(null); } }
- https://blog.csdn.net/cxz2003…
07.Android引入flutter实质
-
如何了解Android引入flutter页面
- Android我的项目引入Flutter实质上是将Flutter编写的Widget嵌入到Activity中,相似于WebView,容器Activity相当于WebView,route相当于url,有两种形式FlutterView和FlutterFragment。页面间的跳转和传参能够借助MethodChannel来实现。
08.Flutter启动加载优化
8.1 剖析flutter的启动页面流程
-
通过flutter引擎,整个flutter引擎的相干初始化工作在onCreate办法里开始的
protected void onCreate(@Nullable Bundle savedInstanceState) { this.switchLaunchThemeForNormalTheme(); super.onCreate(savedInstanceState); this.lifecycle.handleLifecycleEvent(Event.ON_CREATE); this.delegate = new FlutterActivityAndFragmentDelegate(this); //创立绑定引擎等 delegate.onAttach(this); //用于插件、框架复原状态 delegate.onActivityCreated(savedInstanceState); //设置窗口背景通明,暗藏 status bar configureWindowForTransparency(); //从这里剖析,这里是咱们的入口 setContentView(createFlutterView()); this.configureStatusBarForFullscreenFlutterExperience(); }
-
而后接着往下看,会调用到FlutterActivityAndFragmentDelegate类的onCreateView办法
- FlutterActivityAndFragmentDelegate类,flutter的初始化、启动等操作都是委托给它的。
-
大抵理解到,创立了一个FlutterSurfaceView 它继承自surfaceView(咱们的flutter页面也是渲染在这个surface上的)。之后咱们用它初始化一个FlutterView,
@NonNull View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { Log.v("FlutterActivityAndFragmentDelegate", "Creating FlutterView."); this.ensureAlive(); if (this.host.getRenderMode() == RenderMode.surface) { //flutter 利用在surface上显示,所以会进入到这里 FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(this.host.getActivity(), this.host.getTransparencyMode() == TransparencyMode.transparent); this.host.onFlutterSurfaceViewCreated(flutterSurfaceView); //用flutterSurfaceView 初始化了一个 FlutterView this.flutterView = new FlutterView(this.host.getActivity(), flutterSurfaceView); } else { //否则,利用在TextureView上显示 FlutterTextureView flutterTextureView = new FlutterTextureView(this.host.getActivity()); this.host.onFlutterTextureViewCreated(flutterTextureView); //用flutterTextureView 初始化了一个 FlutterView this.flutterView = new FlutterView(this.host.getActivity(), flutterTextureView); } this.flutterView.addOnFirstFrameRenderedListener(this.flutterUiDisplayListener); //创立一个闪屏view - FlutterSplashView this.flutterSplashView = new FlutterSplashView(this.host.getContext()); if (VERSION.SDK_INT >= 17) { this.flutterSplashView.setId(View.generateViewId()); } else { this.flutterSplashView.setId(486947586); } //显示闪屏页 this.flutterSplashView.displayFlutterViewWithSplash(this.flutterView, this.host.provideSplashScreen()); Log.v("FlutterActivityAndFragmentDelegate", "Attaching FlutterEngine to FlutterView."); //所创立surface 绑定到engine上 this.flutterView.attachToFlutterEngine(this.flutterEngine); return this.flutterSplashView; }
-
随后咱们再创立一个FlutterSplashView (继承FrameLayout)。重要看调用displayFlutterViewWithSplash()办法。
-
看到这里可知,通过splashScreen(是个接口),具体看接口实现类,而后创立一个splashScreenView,最初增加到flutter的布局中
public void displayFlutterViewWithSplash(@NonNull FlutterView flutterView, @Nullable SplashScreen splashScreen) { if (this.splashScreenView != null) { this.removeView(this.splashScreenView); } //省略大量代码 this.flutterView = flutterView; this.addView(flutterView); this.splashScreen = splashScreen; if (splashScreen != null) { if (this.isSplashScreenNeededNow()) { Log.v(TAG, "Showing splash screen UI."); this.splashScreenView = splashScreen.createSplashView(this.getContext(), this.splashScreenState); //增加 splashScreenView this.addView(this.splashScreenView); flutterView.addOnFirstFrameRenderedListener(this.flutterUiDisplayListener); } } }
-
那么什么时候移除这个启动Splash布局呢?在创立FlutterSplashView时,增加了一个实现事件的监听,当flutter加载胜利后才将它移除。
public FlutterSplashView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.onTransitionComplete = new Runnable() { public void run() { FlutterSplashView.this.removeView(FlutterSplashView.this.splashScreenView); FlutterSplashView.this.previousCompletedSplashIsolate = FlutterSplashView.this.transitioningIsolateId; } }; this.setSaveEnabled(true); }
-
-
得出结论
- 能够发现在闪屏页的显示到引擎的启动及flutter 页面的显示会有一个很长的过程,而直到flutter 页面的显示,这个闪屏页才会被移除掉。
8.2 如何优化flutter启动屏
-
第一种计划
-
Flutter因为引擎的创立和初始化须要肯定工夫,所以也提供了一个过渡计划(默认是白屏)。如下所示,你能够设置一下背景
AndroidManifest.xml下的 <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background"/>
-
-
第二种计划
@Nullable @Override public SplashScreen provideSplashScreen() { //创立自定义flutter启动屏view return new FlutterSplashView(); } public class FlutterSplashView implements SplashScreen { @Nullable @Override public View createSplashView(@NonNull Context context, @Nullable Bundle savedInstanceState) { View v = new View(context); v.setBackgroundColor(Color.WHITE); return v; } @Override public void transitionToFlutter(@NonNull Runnable onTransitionComplete) { onTransitionComplete.run(); } }
发表回复