Flutter啟動(dòng)流程的深入解析
前言
Flutter是怎么啟動(dòng)起來(lái)的,是在Android的Activity的啟動(dòng)之后嗎?等等這樣的問(wèn)題,在這個(gè)文章中將被解答。
從MainActivity開始
新創(chuàng)建一個(gè)Flutter項(xiàng)目,在清單文件中默認(rèn)被啟動(dòng)的Activity是MainActivity,而MainActivity繼承的是FlutterActivity。那么問(wèn)題好像簡(jiǎn)單了,我們分析一下FlutterActivity,下面是MainActivity的代碼。
public class MainActivity extends FlutterActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); } }
上面的源碼很簡(jiǎn)單,有兩個(gè)點(diǎn)需要關(guān)注,第一個(gè)就是在MainActivity.onCreate()
中調(diào)用了GeneratedPluginRegistrant.registerWith()
這個(gè)方法,第二個(gè)是MainActivity繼承自FlutterActivity,我們對(duì)這兩個(gè)關(guān)注點(diǎn)依次進(jìn)行分析。
GeneratedPluginRegistrant.registerWith()分析
我們查看GeneratedPluginRegistrant,發(fā)現(xiàn)這個(gè)類是Android Studio自動(dòng)生成的,并且不建議修改,這個(gè)類也非常簡(jiǎn)單,下面是GeneratedPluginRegistrant的代碼。
public final class GeneratedPluginRegistrant { public static void registerWith(PluginRegistry registry) { if (alreadyRegisteredWith(registry)) { return; } } private static boolean alreadyRegisteredWith(PluginRegistry registry) { final String key = GeneratedPluginRegistrant.class.getCanonicalName(); if (registry.hasPlugin(key)) { return true; } registry.registrarFor(key); return false; } }
如果PluginRegistry已經(jīng)包含了GeneratedPluginRegistrant就直接返回true,如沒有就調(diào)用PluginRegistry.registrarFor()
進(jìn)行注冊(cè)。
我們分析一下PluginRegistry,看看是怎么注冊(cè)的,發(fā)現(xiàn)PluginRegistry是一個(gè)接口,下面是PluginRegistry的代碼。
public interface PluginRegistry { Registrar registrarFor(String pluginKey); }
PluginRegistry的實(shí)現(xiàn)是誰(shuí)呢?是FlutterActivity,下面開發(fā)分析FlutterActivity,暫時(shí)看FlutterActivity比較重要,因?yàn)檫@個(gè)類是MainActivity的父類,還是PluginRegistry的具體實(shí)現(xiàn)類。
FlutterActivity分析
下面是FlutterActivity的代碼。
public class FlutterActivity extends Activity implements FlutterView.Provider, PluginRegistry, ViewFactory { private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this); private final FlutterActivityEvents eventDelegate = delegate; private final FlutterView.Provider viewProvider = delegate; private final PluginRegistry pluginRegistry = delegate; @Override public final boolean hasPlugin(String key) { return pluginRegistry.hasPlugin(key); } @Override public final Registrar registrarFor(String pluginKey) { return pluginRegistry.registrarFor(pluginKey); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); eventDelegate.onCreate(savedInstanceState); } @Override protected void onDestroy() { eventDelegate.onDestroy(); super.onDestroy(); } @Override protected void onStop() { eventDelegate.onStop(); super.onStop(); } //省略了一些代碼 }
從上面的代碼中可以看出來(lái),F(xiàn)lutterActivity是繼承Activity和實(shí)現(xiàn)了PluginRegistry。分析一下onCreate,onStop,onDestroy這些生命周期方法被FlutterActivity.eventDelegate
代理了,這個(gè)時(shí)候我們明白了,F(xiàn)lutterActivity就是一個(gè)空殼,真正實(shí)現(xiàn)是代理類FlutterActivityDelegate。
我們具體看一下,下面是FlutterActivity.onCreate()
的代碼。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); eventDelegate.onCreate(savedInstanceState); }
FlutterActivity.$onCreate()
比較簡(jiǎn)單,調(diào)用了super的onCreate()
和eventDelegate.onCreate()
,也就是調(diào)用了代理類的onCreate方法,下面分析FlutterActivityDelegate。
FlutterActivityDelegate分析
從上面的分析可以得出結(jié)論,F(xiàn)lutterActivity什么都沒有做,都交個(gè)了FlutterActivityDelegate去干,這里類實(shí)現(xiàn)了PluginRegistry,下面是FlutterActivityDelegate的代碼。
public final class FlutterActivityDelegate implements FlutterActivityEvents, FlutterView.Provider, PluginRegistry { @Override public void onCreate(Bundle savedInstanceState) { } }
還是先分析FlutterActivityDelegate.onCreate()
,這個(gè)真正干活的onCreate方法還是比較復(fù)雜的,下面是FlutterActivityDelegate.onCreate()
的代碼。
@Override public void onCreate(Bundle savedInstanceState) { String[] args = getArgsFromIntent(activity.getIntent());//1 FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);//2 flutterView = viewFactory.createFlutterView(activity);//3 if (flutterView == null) { FlutterNativeView nativeView = viewFactory.createFlutterNativeView(); flutterView = new FlutterView(activity, null, nativeView);//4 flutterView.setLayoutParams(matchParent); activity.setContentView(flutterView);//5 launchView = createLaunchView(); if (launchView != null) { addLaunchView(); } } if (loadIntent(activity.getIntent())) { return; } String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext()); if (appBundlePath != null) { runBundle(appBundlePath); } }
注釋1
得到了一些參數(shù),這些參數(shù)是干啥用的?我們拿一個(gè)trace-startup參數(shù)為例進(jìn)行簡(jiǎn)單介紹下面是FlutterActivityDelegate.getArgsFromIntent()
的代碼。
private static String[] getArgsFromIntent(Intent intent) { ArrayList<String> args = new ArrayList<>(); if (intent.getBooleanExtra("trace-startup", false)) { args.add("--trace-startup"); } if (intent.getBooleanExtra("start-paused", false)) { args.add("--start-paused"); } if (!args.isEmpty()) { String[] argsArray = new String[args.size()]; return args.toArray(argsArray); } return null; }
當(dāng)你安裝一個(gè)App的時(shí)候,可以用下面這個(gè)命令,
flutter run --trace-startup --profile
安裝完之后會(huì)生下面這個(gè)json,
{ "engineEnterTimestampMicros": 273508186457, "timeToFrameworkInitMicros": 271420, "timeToFirstFrameMicros": 469796, "timeAfterFrameworkInitMicros": 198376 }
這個(gè)json會(huì)顯示進(jìn)入Flutter引擎的時(shí)間和展示應(yīng)用第一幀的時(shí)間等等。
注釋2
調(diào)用 FlutterMain.ensureInitializationComplete()
,這方法初始化了Flutter,下面是ensureInitializationComplete的代碼。
public static void ensureInitializationComplete(Context applicationContext, String[] args) { if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("ensureInitializationComplete must be called on the main thread"); } try { sResourceExtractor.waitForCompletion(); List<String> shellArgs = new ArrayList<>(); shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat"); String appBundlePath = findAppBundlePath(applicationContext); String appStoragePath = PathUtils.getFilesDir(applicationContext); nativeInit(applicationContext, shellArgs.toArray(new String[0]), appBundlePath, appStoragePath, engineCachesPath);//1 } catch (Exception e) { Log.e(TAG, "Flutter initialization failed.", e); throw new RuntimeException(e); } } //native方法 private static native void nativeInit(Context context, String[] args, String bundlePath, String appStoragePath, String engineCachesPath);
先判斷是不是主線程,如果不是主線程直接拋出異常。初始化參數(shù)調(diào)用 FlutterMain.nativeInit()
方法,這個(gè)方法是native方法,主要的用途是初始化Flutter。
注釋3
ViewFactory是一個(gè)接口,ViewFactory.createFlutterView()
的具體實(shí)現(xiàn)有兩個(gè),分別是FlutterActivity.createFlutterView()
和FlutterFragmentActivity.createFlutterView()
現(xiàn)在這個(gè)兩個(gè)具體實(shí)現(xiàn)都返回null,也就是一定會(huì)走到注釋4。
注釋4
創(chuàng)建FlutterView,那么FlutterView是什么呢?看一下類的聲明,下面是FlutterView的聲明的代碼,
public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry }
原來(lái)是一 SurfaceView,這個(gè)就很容易理解了。
注釋5
關(guān)鍵來(lái)了,下面是調(diào)用setContentView的代碼,
activity.setContentView(flutterView);
把FlutterView加載到Activity中,折騰了半天,就是做了這樣一件事,說(shuō)白了就是創(chuàng)建了一個(gè)FlutterView,并且把這個(gè)view顯示到屏幕上。
下面是Flutter的啟動(dòng)流程圖。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
android studio開發(fā)實(shí)現(xiàn)APP開機(jī)自啟動(dòng)
這篇文章主要為大家詳細(xì)介紹了android studio開發(fā)實(shí)現(xiàn)APP開機(jī)自啟動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-052021最新Android筆試題總結(jié)美團(tuán)Android崗職能要求
這篇文章主要介紹了2021最新Android筆試題總結(jié)以及美團(tuán)Android崗職能要求,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08Android使用Intent實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了Android使用Intent實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android 連接Wifi和創(chuàng)建Wifi熱點(diǎn)的實(shí)例
本篇文章介紹了Android 連接Wifi和創(chuàng)建Wifi熱點(diǎn),小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧。2016-10-10Jenkins打包android應(yīng)用時(shí)自動(dòng)簽名apk詳解
這篇文章主要介紹了Jenkins打包android應(yīng)用時(shí)自動(dòng)簽名apk詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07Android多個(gè)TAB選項(xiàng)卡切換效果
這篇文章主要介紹了Android多個(gè)TAB選項(xiàng)卡切換效果的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-04-04Android雙重SurfaceView實(shí)現(xiàn)彈幕效果
這篇文章主要為大家詳細(xì)介紹了Android雙重SurfaceView實(shí)現(xiàn)彈幕效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11Android編程檢測(cè)手機(jī)錄音權(quán)限是否打開的方法
這篇文章主要介紹了Android編程檢測(cè)手機(jī)錄音權(quán)限是否打開的方法,涉及Android針對(duì)音頻操作的相關(guān)技巧與注意事項(xiàng),需要的朋友可以參考下2017-11-11Android開啟ADB網(wǎng)絡(luò)調(diào)試方法
今天小編就為大家分享一篇Android開啟ADB網(wǎng)絡(luò)調(diào)試方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08