問題
Cannot fit requested classes in a single dex file (# methods: 66370 > 65536)
原因分析
主要原因是你的專案貌似有點大,已經超過65k個方法。一個dex已經裝不下了,需要個多個dex,也就是multidex ,因為Android系統定義總方法數是一個short int,short int 最大值為65536。
解決方案
- 在app module中的build.gradle中新增依賴
implementation 'com.android.support:multidex:1.0.3' // dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' //新增到此處 implementation 'com.android.support:multidex:1.0.3' }
- 在app module中的build.gradle中的defaultConfig中新增以下程式碼
android { compileSdkVersion 28 defaultConfig { applicationId "com.example.demo" minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //新增到此處 multiDexEnabled true } }
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());
}
};
連結:https://www.jianshu.com/p/4f0651241956\
本作品採用《CC 協議》,轉載必須註明作者和本文連結