程式碼是基於io.flutter.embedding.android包下,看網上好多程式碼都是基於io.flutter.app目錄下的。其實在flutter1.12之後就建議使用前者了。
下面講的是純Flutter專案,不是混合開發,混合的話是有區別的。以Android應用為例,啟動還是先走Application和指定作為Launcher的Activity。而系統預設的會使用繼承FlutterAppication的一個Application和繼承FlutterActivity的MainActivity。所以app的啟動可以先分析下FlutterApplication和FlutterActivity 。
FutterApplication
package io.flutter.app;
import android.app.Activity;
import android.app.Application;
import androidx.annotation.CallSuper;
import io.flutter.view.FlutterMain;
/**
* Flutter implementation of {@link android.app.Application}, managing application-level global
* initializations.
*
* <p>Using this {@link android.app.Application} is not required when using APIs in the package
* {@code io.flutter.embedding.android} since they self-initialize on first use.
*/
public class FlutterApplication extends Application {
@Override
@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity() {
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity) {
this.mCurrentActivity = mCurrentActivity;
}
}
複製程式碼
FlutterApplication是繼承於Application,主要是在onCreate()中調了FlutterMain.startInitialization(this)。
FlutterMain
/**
* A legacy class to initialize the Flutter engine.
*
* <p>Replaced by {@link io.flutter.embedding.engine.loader.FlutterLoader}.
*/
public class FlutterMain {
...
}
複製程式碼
看上面的註釋,一個初始化FLutter引擎的舊類,現在被FlutterLoader給替換了。我們看裡面程式碼,確實FlutterMain就是一個空殼,具體都是呼叫FLutterLoader實現的。 初始化:
public static void startInitialization(
@NonNull Context applicationContext, @NonNull Settings settings) {
if (isRunningInRobolectricTest) {
return;
}
FlutterLoader.Settings newSettings = new FlutterLoader.Settings();
newSettings.setLogTag(settings.getLogTag());
FlutterLoader.getInstance().startInitialization(applicationContext, newSettings);
}
複製程式碼
這方法將載入Flutter引擎的本機庫以啟用後續的JNI呼叫。也開始查詢和解壓縮應用程式APK中打包的Dart資源。
FlutterLoader
我們看下FlutterLoader的startInitialization方法,其實它主要做了以下幾件事:
- 初始化配置
- 初始化資源
- 載入Flutter.so
- 註冊VsyncWatcher
- 記錄初始化的耗時
下面看下原始碼
public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
// Do not run startInitialization more than once.
if (this.settings != null) {
return;
}
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
}
// Ensure that the context is actually the application context.
applicationContext = applicationContext.getApplicationContext();
this.settings = settings;
long initStartTimestampMillis = SystemClock.uptimeMillis();
initConfig(applicationContext);
initResources(applicationContext);
System.loadLibrary("flutter");
VsyncWaiter.getInstance(
(WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE))
.init();
// We record the initialization time using SystemClock because at the start of the
// initialization we have not yet loaded the native library to call into dart_tools_api.h.
// To get Timeline timestamp of the start of initialization we simply subtract the delta
// from the Timeline timestamp at the current moment (the assumption is that the overhead
// of the JNI call is negligible).
long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
}
複製程式碼
可以看到方法註解跟FlutterMain一毛一樣。
// Do not run startInitialization more than once.
if (this.settings != null) {
return;
}
複製程式碼
判斷保證了FlutterMain.startInitialization無法多次呼叫。因為之前呼叫會設定settings。
FlutterLoader.Settings newSettings = new FlutterLoader.Settings();
newSettings.setLogTag(settings.getLogTag());
複製程式碼
下面一行的程式碼要求Flutter引擎初始化必選在主執行緒
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
}
複製程式碼
初始化配置
從Manifest.xml中初始化一些引數
/**
* Initialize our Flutter config values by obtaining them from the manifest XML file, falling back
* to default values.
*/
private void initConfig(@NonNull Context applicationContext) {
Bundle metadata = getApplicationInfo(applicationContext).metaData;
// There isn't a `<meta-data>` tag as a direct child of `<application>` in
// `AndroidManifest.xml`.
if (metadata == null) {
return;
}
aotSharedLibraryName =
metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, DEFAULT_AOT_SHARED_LIBRARY_NAME);
flutterAssetsDir =
metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, DEFAULT_FLUTTER_ASSETS_DIR);
vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, DEFAULT_VM_SNAPSHOT_DATA);
isolateSnapshotData =
metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, DEFAULT_ISOLATE_SNAPSHOT_DATA);
}
複製程式碼
如果不設定的話都是預設引數
/** Finds Flutter resources in an application APK and also loads Flutter's native library. */
public class FlutterLoader {
private static final String TAG = "FlutterLoader";
// Must match values in flutter::switches
private static final String AOT_SHARED_LIBRARY_NAME = "aot-shared-library-name";
private static final String SNAPSHOT_ASSET_PATH_KEY = "snapshot-asset-path";
private static final String VM_SNAPSHOT_DATA_KEY = "vm-snapshot-data";
private static final String ISOLATE_SNAPSHOT_DATA_KEY = "isolate-snapshot-data";
private static final String FLUTTER_ASSETS_DIR_KEY = "flutter-assets-dir";
// XML Attribute keys supported in AndroidManifest.xml
private static final String PUBLIC_AOT_SHARED_LIBRARY_NAME =
FlutterLoader.class.getName() + '.' + AOT_SHARED_LIBRARY_NAME;
private static final String PUBLIC_VM_SNAPSHOT_DATA_KEY =
FlutterLoader.class.getName() + '.' + VM_SNAPSHOT_DATA_KEY;
private static final String PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY =
FlutterLoader.class.getName() + '.' + ISOLATE_SNAPSHOT_DATA_KEY;
private static final String PUBLIC_FLUTTER_ASSETS_DIR_KEY =
FlutterLoader.class.getName() + '.' + FLUTTER_ASSETS_DIR_KEY;
// 用於預編譯快照元件的資源名稱。
private static final String DEFAULT_AOT_SHARED_LIBRARY_NAME = "libapp.so";
private static final String DEFAULT_VM_SNAPSHOT_DATA = "vm_snapshot_data";
private static final String DEFAULT_ISOLATE_SNAPSHOT_DATA = "isolate_snapshot_data";
private static final String DEFAULT_LIBRARY = "libflutter.so";
private static final String DEFAULT_KERNEL_BLOB = "kernel_blob.bin";
private static final String DEFAULT_FLUTTER_ASSETS_DIR = "flutter_assets";
// Mutable because default values can be overridden via config properties
private String aotSharedLibraryName = DEFAULT_AOT_SHARED_LIBRARY_NAME;
private String vmSnapshotData = DEFAULT_VM_SNAPSHOT_DATA;
private String isolateSnapshotData = DEFAULT_ISOLATE_SNAPSHOT_DATA;
private String flutterAssetsDir = DEFAULT_FLUTTER_ASSETS_DIR;
...
}
複製程式碼
其實initConfig()就是給aotSharedLibraryName,vmSnapshotData,isolateSnapshotData,flutterAssetsDir這四個變數賦值,通過命名我們能大體猜出這四個變數代表了什麼。 aotSharedLibraryName看意思就是通過aot打成的二級制包。預設名是libapp.so,其實裡面就是Flutter專案中通過Dart實現的業務程式碼,現在被打成so庫。 flutterAssetsDir應該是asset的路徑,通過該路徑可以找到asset中資原始檔。 其他兩個看名字就是和虛擬機器還有Isolate相關。
初始化資源
下面看資源初始化的方法:initResources()
/** Extract assets out of the APK that need to be cached as uncompressed files on disk. */
private void initResources(@NonNull Context applicationContext) {
new ResourceCleaner(applicationContext).start();
if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
final String dataDirPath = PathUtils.getDataDirectory(applicationContext);
final String packageName = applicationContext.getPackageName();
final PackageManager packageManager = applicationContext.getPackageManager();
final AssetManager assetManager = applicationContext.getResources().getAssets();
resourceExtractor =
new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);
// In debug/JIT mode these assets will be written to disk and then
// mapped into memory so they can be provided to the Dart VM.
resourceExtractor
.addResource(fullAssetPathFrom(vmSnapshotData))
.addResource(fullAssetPathFrom(isolateSnapshotData))
.addResource(fullAssetPathFrom(DEFAULT_KERNEL_BLOB));
resourceExtractor.start();
}
}
複製程式碼
先清了下資源,然後載入了Asset中的資源到記憶體這樣Dart虛擬機器才能使用。Flutter中的圖片字型等資源在打包後都會被放置在asset目錄下。vmSnapshotData,isolateSnapshotData初始化的變數在這用到了。但是,這個是DEBUG或者JIT模式下的方法,所以說release包載入資源的方式應該是不一樣的
載入Flutter.so
System.loadLibrary("flutter");
複製程式碼
這裡是載入二進位制的庫,預設全名應該是libFlutter.so,主要是執行時環境。
註冊VsyncWatcher
VsyncWaiter.getInstance(
(WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE))
.init();
複製程式碼
這個還沒細看,應該是註冊後每次有脈衝就會接到通知,正常是每秒60次吧(這是猜測的哈)。
記錄初始化的耗時
long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
複製程式碼
可以看到FlutterApplica基本上就是初始化一些配置,載入了資源和Flutter.so。
FlutterActivity
public class FlutterActivity extends Activity
implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
...
// Delegate that runs all lifecycle and OS hook logic that is common between
// FlutterActivity and FlutterFragment. See the FlutterActivityAndFragmentDelegate
// implementation for details about why it exists.
@VisibleForTesting protected FlutterActivityAndFragmentDelegate delegate;
@NonNull private LifecycleRegistry lifecycle;
public FlutterActivity() {
lifecycle = new LifecycleRegistry(this);
}
@VisibleForTesting
/* package */ void setDelegate(@NonNull FlutterActivityAndFragmentDelegate delegate) {
this.delegate = delegate;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
switchLaunchThemeForNormalTheme();
super.onCreate(savedInstanceState);
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(this);
delegate.onActivityCreated(savedInstanceState);
configureWindowForTransparency();
setContentView(createFlutterView());
configureStatusBarForFullscreenFlutterExperience();
}
...
}
複製程式碼
看下FlutterActivity的onCreate()中其實就兩個比較重要的步驟。繫結Delegate和createFlutterView。
setContentView(createFlutterView());
複製程式碼
FlutterActivityAndFragmentDelegate
FlutterActivity的onCreate()總共FlutterActivityAndFragmentDelegate總共做了三步:
- 建立Delegate,
- 繫結
- onActivityCreated。
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(this);
delegate.onActivityCreated(savedInstanceState);
複製程式碼
構造Delegate
看下它的建構函式:
FlutterActivityAndFragmentDelegate(@NonNull Host host) {
this.host = host;
}
複製程式碼
傳入了一個Host,這個Host被FlutterActivity給實現:
public class FlutterActivity extends Activity
implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner
複製程式碼
從FlutterActivity的繼承和實現可以看出,FlutterActivity除了Activity和getLifecycle等方法,其他的都是對Host的實現。也可以理解為針對Flutter相關的操作都定義在Host中了。
/**
* The {@link FlutterActivity} or {@link FlutterFragment} that owns this {@code
* FlutterActivityAndFragmentDelegate}.
*/
/* package */ interface Host
extends SplashScreenProvider, FlutterEngineProvider, FlutterEngineConfigurator {
複製程式碼
大體有一下
onAttach
該方法原始碼如下:
/**
* Invoke this method from {@code Activity#onCreate(Bundle)} or {@code
* Fragment#onAttach(Context)}.
*
* <p>This method does the following:
*
* <p>
*
* <ol>
* <li>Initializes the Flutter system.
* <li>Obtains or creates a {@link FlutterEngine}.
* <li>Creates and configures a {@link PlatformPlugin}.
* <li>Attaches the {@link FlutterEngine} to the surrounding {@code Activity}, if desired.
* <li>Configures the {@link FlutterEngine} via {@link
* Host#configureFlutterEngine(FlutterEngine)}.
* </ol>
*/
void onAttach(@NonNull Context context) {
ensureAlive();
// When "retain instance" is true, the FlutterEngine will survive configuration
// changes. Therefore, we create a new one only if one does not already exist.
if (flutterEngine == null) {
setupFlutterEngine();
}
// Regardless of whether or not a FlutterEngine already existed, the PlatformPlugin
// is bound to a specific Activity. Therefore, it needs to be created and configured
// every time this Fragment attaches to a new Activity.
// TODO(mattcarroll): the PlatformPlugin needs to be reimagined because it implicitly takes
// control of the entire window. This is unacceptable for non-fullscreen
// use-cases.
platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
if (host.shouldAttachEngineToActivity()) {
// Notify any plugins that are currently attached to our FlutterEngine that they
// are now attached to an Activity.
//
// Passing this Fragment's Lifecycle should be sufficient because as long as this Fragment
// is attached to its Activity, the lifecycles should be in sync. Once this Fragment is
// detached from its Activity, that Activity will be detached from the FlutterEngine, too,
// which means there shouldn't be any possibility for the Fragment Lifecycle to get out of
// sync with the Activity. We use the Fragment's Lifecycle because it is possible that the
// attached Activity is not a LifecycleOwner.
Log.v(TAG, "Attaching FlutterEngine to the Activity that owns this Fragment.");
flutterEngine
.getActivityControlSurface()
.attachToActivity(host.getActivity(), host.getLifecycle());
}
host.configureFlutterEngine(flutterEngine);
}
複製程式碼
該方法會在Activity的onCreate()和Fragment的onAttach()方法中呼叫。這個方法做了以下操作:
- 初始化了Flutter系統
- 獲取或者建立了Flutter引擎
- 建立並配置了PlatformPlugin
- 如果需要,將Flutter引擎附加到周圍的 Activity
- 通過configureFlutterEngine(FlutterEngine)來配置Flutter引擎
獲取或者建立Flutter引擎
在確保當前delegate沒有被釋放並且當前delegate沒有引擎的情況下,我們開發設定一個引擎。
ensureAlive();
// When "retain instance" is true, the FlutterEngine will survive configuration
// changes. Therefore, we create a new one only if one does not already exist.
if (flutterEngine == null) {
setupFlutterEngine();
}
複製程式碼
設定引擎主要是三步:
- 如果有快取的引擎,使用快取的引擎
- 使用FlutterActivity子類中的provideFlutterEngine()提供了引擎
- 如果上面兩種都沒有,就自己例項一個引擎
@VisibleForTesting
/* package */ void setupFlutterEngine() {
// First, check if the host wants to use a cached FlutterEngine.
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;
}
// Second, defer to subclasses for a custom FlutterEngine.
flutterEngine = host.provideFlutterEngine(host.getContext());
if (flutterEngine != null) {
isFlutterEngineFromHost = true;
return;
}
// Our host did not provide a custom FlutterEngine. Create a FlutterEngine to back our
// FlutterView.
Log.v(
TAG,
"No preferred FlutterEngine was provided. Creating a new FlutterEngine for"
+ " this FlutterFragment.");
flutterEngine =
new FlutterEngine(
host.getContext(),
host.getFlutterShellArgs().toArray(),
/*automaticallyRegisterPlugins=*/ false);
isFlutterEngineFromHost = false;
複製程式碼
註冊常用原生外掛到引擎
無論FlutterEngine是否已存在,PlatformPlugin都繫結到特定的Activity。因此,每次此Fragment附加到新的Activity時,都需要建立和配置它的一些平臺外掛。
platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
複製程式碼
具體實現在FlutterActivity
@Nullable
@Override
public PlatformPlugin providePlatformPlugin(
@Nullable Activity activity, @NonNull FlutterEngine flutterEngine) {
if (activity != null) {
return new PlatformPlugin(getActivity(), flutterEngine.getPlatformChannel());
} else {
return null;
}
}
複製程式碼
public PlatformPlugin(Activity activity, PlatformChannel platformChannel) {
this.activity = activity;
this.platformChannel = platformChannel;
this.platformChannel.setPlatformMessageHandler(mPlatformMessageHandler);
mEnabledOverlays = DEFAULT_SYSTEM_UI;
}
複製程式碼
然後主要就做了一件事,就是對當前引擎的PlatformChannel設定MessageHandler。具體設定哪些外掛如下:
private final PlatformChannel.PlatformMessageHandler mPlatformMessageHandler =
new PlatformChannel.PlatformMessageHandler() {
@Override
public void playSystemSound(@NonNull PlatformChannel.SoundType soundType) {
PlatformPlugin.this.playSystemSound(soundType);
}
@Override
public void vibrateHapticFeedback(
@NonNull PlatformChannel.HapticFeedbackType feedbackType) {
PlatformPlugin.this.vibrateHapticFeedback(feedbackType);
}
@Override
public void setPreferredOrientations(int androidOrientation) {
setSystemChromePreferredOrientations(androidOrientation);
}
@Override
public void setApplicationSwitcherDescription(
@NonNull PlatformChannel.AppSwitcherDescription description) {
setSystemChromeApplicationSwitcherDescription(description);
}
@Override
public void showSystemOverlays(@NonNull List<PlatformChannel.SystemUiOverlay> overlays) {
setSystemChromeEnabledSystemUIOverlays(overlays);
}
@Override
public void restoreSystemUiOverlays() {
restoreSystemChromeSystemUIOverlays();
}
@Override
public void setSystemUiOverlayStyle(
@NonNull PlatformChannel.SystemChromeStyle systemUiOverlayStyle) {
setSystemChromeSystemUIOverlayStyle(systemUiOverlayStyle);
}
@Override
public void popSystemNavigator() {
PlatformPlugin.this.popSystemNavigator();
}
@Override
public CharSequence getClipboardData(
@Nullable PlatformChannel.ClipboardContentFormat format) {
return PlatformPlugin.this.getClipboardData(format);
}
@Override
public void setClipboardData(@NonNull String text) {
PlatformPlugin.this.setClipboardData(text);
}
@Override
public List<Rect> getSystemGestureExclusionRects() {
return PlatformPlugin.this.getSystemGestureExclusionRects();
}
@Override
public void setSystemGestureExclusionRects(@NonNull ArrayList<Rect> rects) {
PlatformPlugin.this.setSystemGestureExclusionRects(rects);
}
};
複製程式碼
就是音量震動等需要呼叫系統原生功能的東西。
將引擎上的外掛綁到Activity上
flutterEngine
.getActivityControlSurface()
.attachToActivity(host.getActivity(), host.getLifecycle());
複製程式碼
對外暴露配置當前引擎的方法
host.configureFlutterEngine(flutterEngine);
/** Hook for the host to configure the {@link FlutterEngine} as desired. */
void configureFlutterEngine(@NonNull FlutterEngine flutterEngine);
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
registerPlugins(flutterEngine);
}
private static void registerPlugins(@NonNull FlutterEngine flutterEngine) {
try {
Class<?> generatedPluginRegistrant =
Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
Method registrationMethod =
generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
registrationMethod.invoke(null, flutterEngine);
} catch (Exception e) {
Log.w(
TAG,
"Tried to automatically register plugins with FlutterEngine ("
+ flutterEngine
+ ") but could not find and invoke the GeneratedPluginRegistrant.");
}
}
複製程式碼
其實最後這一步就是呼叫了FlutterActivity中的registerPlugins()方法。
作用是將Flutter專案中 pubspec.yaml檔案中依賴的三方外掛全部註冊上。 (note:其實在1.12之前這一步是需要開發者自己做的,但是1.1.2之後就自動幫你實現了)
onActivityCreated
給外掛恢復狀態的機會
void onActivityCreated(@Nullable Bundle bundle) {
Log.v(TAG, "onActivityCreated. Giving plugins an opportunity to restore state.");
ensureAlive();
if (host.shouldAttachEngineToActivity()) {
flutterEngine.getActivityControlSurface().onRestoreInstanceState(bundle);
}
}
複製程式碼
createFlutterView
上面的內容都是些關於引擎和外掛的配置。但是具體如何顯示Flutter的檢視還沒涉及。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
setContentView(createFlutterView());
...
}
複製程式碼
從上面程式碼可以看到FlutterActivity具體顯示的檢視由createFlutterView()決定,而具體實現又在delegate中
@NonNull
private View createFlutterView() {
return delegate.onCreateView(
null /* inflater */, null /* container */, null /* savedInstanceState */);
}
@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);
// Allow our host to customize FlutterSurfaceView, if desired.
host.onFlutterSurfaceViewCreated(flutterSurfaceView);
// Create the FlutterView that owns the FlutterSurfaceView.
flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
} else {
FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
// Allow our host to customize FlutterSurfaceView, if desired.
host.onFlutterTextureViewCreated(flutterTextureView);
// Create the FlutterView that owns the FlutterTextureView.
flutterView = new FlutterView(host.getActivity(), flutterTextureView);
}
// Add listener to be notified when Flutter renders its first frame.
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
flutterSplashView = new FlutterSplashView(host.getContext());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
flutterSplashView.setId(View.generateViewId());
} else {
flutterSplashView.setId(486947586);
}
flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
Log.v(TAG, "Attaching FlutterEngine to FlutterView.");
flutterView.attachToFlutterEngine(flutterEngine);
return flutterSplashView;
}
複製程式碼
我們通過上面的程式碼可以發現最後返回的不是FlutterView,而是FlutterSplashView。還有FlutterView的建立需要使用到FlutterSurfaceView或者FlutterTextureView。這還是很有意思。下面具體看下這個方法主要做了什麼:
- 建立FlutterView。
- FlutterView新增第一幀繪製成功回撥。
- 建立FlutterSplashView並掛載到View樹中。
- 將FlutterView交給FlutterSplashView並掛載到引擎。
建立FlutterView
首先需要知道當前配置的RenderModel。如果RenderModel是surface則需要先建立FlutterSurfaceView,如果是texture則需要建立FlutterTexture。然後再通過FlutterSurfaceView和FlutterTextureView建立FlutterView。只是看名字我們可以猜測FlutterView的具體UI是通過SurfaceView或者TexutureView來顯示的。而FlutterSurfaceView和FlutterTextureView也分別整合原生的SurfaceView和TextureView。
系統推薦使用RenderModel為surface。理由是這樣效能更高。其實這個跟你再使用SurfaceView或者TextureView實現視訊播放器是一樣的。
FlutterSplashView
**
* {@code View} that displays a {@link SplashScreen} until a given {@link FlutterView} renders its
* first frame.
*/
/* package */ final class FlutterSplashView extends FrameLayout {
複製程式碼
看類註解理解為:一個在FlutterView繪製完第一幀前用來顯示SplashScreen的View。 如果在使用debug模式編寫Flutter會發現FlutterView的顯示是有點慢的,所以此時先顯示一個之前設定的splashScreen當Flutter第一幀繪製完,再將splashScreen移除。
除了上述內容外,此處主要還把FlutterSplashView掛載到了當前的View樹種。並將FlutterView新增到了FlutterSplashView中。最後還把當前的FlutterView關聯到了當前Activity的引擎上,因為FlutterView是依賴於Flutter引擎繪製。
這些都完成後,FlutterActivity的onCreate()就執行完了,此時等待FlutterView第一幀繪製完就能顯示Flutter的檢視了。