Flutter github#5259是一样的问题
二话不说,先上代码,下面这样可以解决问题
void main(){
runApp(MyApp());
}
改为
import 'dart:ui';//window需要import ui库
void main(){
//如果size是0,则设置回调,在回调中runApp
if(window.physicalSize.isEmpty){
window.onMetricsChanged = (){
//在回调中,size仍然有可能是0
if(!window.physicalSize.isEmpty){
window.onMetricsChanged = null;
runApp(MyApp());
}
};
} else{
//如果size非0,则直接runApp
runApp(MyApp());
}
}
分析
这段代码里有两个东西需要了解一下的,第一个是window.onMetricsChanged
,源码的注释是这样写的
/// A callback that is invoked whenever the [devicePixelRatio],
/// [physicalSize], [padding], or [viewInsets] values change, for example
/// when the device is rotated or when the application is resized (e.g. when
/// showing applications side-by-side on Android).
也就是当devicePixelRatio、physicalSize、padding、viewInsets
这几个东西变化时会触发的回调,其中屏幕大小就是physicalSize
第二个是physicalSize
,上面说了这个是屏幕大小,但是它一开始是0*0,直到Flutter初始化时将它赋值为屏幕大小才能获取到非0的值
好了,说完了上面两个东西,就来说说问题。问题的坑点在于,mian()
方法并不是在Flutter给physicalSize
赋值后才运行的,两者并没有固定的先后顺序,从测试来看,跟设备的性能有关
之前的错误解法
之前是下面这样写的,然后在新ipad air的profile模式下以及所有机型的debug模式下都会白屏,只有比较旧的mini4不会白屏
void main(){
window.onMetricsChanged = (){
runApp(MyApp());
window.onMetricsChanged = null;
};
}
经排查,发现原因是mini够慢,在设置了onMetricsChanged回调后flutter还没有读取到屏幕size,也就还没出触发onMetricsChanged。
然而在新air上,则是几率性的,有时和mini一样,有时在设置onMetricsChanged之前flutter就已经读取了屏幕size了,所以后面一段时间都不会触发onMetricsChanged,导致白屏。更奇怪的是,有时设置的onMetricsChanged倍触发后,仍然是白屏,排查后发现air上不止一次resize,而只有最后一次非0。
所以完整的代码中有这一段保护:
window.onMetricsChanged = (){
//这里仍然有可能是0
if(!window.physicalSize.isEmpty){
window.onMetricsChanged = null;
runApp(MyApp());
}
};
更多
Flutter设计成这样目的应该是想加快应用启动速度,不用等size赋值。这样的话0*0的问题就要开发者自己去考虑了,按照上面的代码,可能会导致应用启动速度稍微慢一丢丢,单可以通过一些办法例如加一个固定大小的闪屏页来弥补上面解法的不足