文章目錄
- 前言
- FlutterActivity分析
- FlutterActivityAndFragmentDelegate.Host分析
- FlutterActivityAndFragmentDelegate分析
- onAttach方法
- onStart方法
- onCreateView方法
- FlutterSplashView分析
- FlutterFragment分析
- FlutterFragmentActivity分析
- onCreate方法
- 需要關聯的方法呼叫
- 總結
前言
之前了解了flutter從啟動到view的創建流程,本文一起來分析下Flutter Android端FlutterActivity和FlutterFragment代碼流程分析,
Flutter Android在創建新Flutter專案的時候并沒有看到FlutterActivity/FlutterFragment,原因是Flutter Android的原始碼主要在maven端,也就是:io.flutter:flutter_embedding_xxx包中,配置地方是在flutter.gradle,可查看文章“深度了解Flutter APP的構建流程”,
如果使用flutter1.12版本之前FlutterActivity位于io.flutter.app.FlutterActivity,該類已經被Deprecated掉了,所以本文以我們專案中使用的版本flutter2.0.6為例,FlutterActivity位于:io.flutter.embedding.android.Flutter,下面我們直接進入FlutterActivity/FlutterFragment分析
FlutterActivity分析
在Flutter App Android端默認的MainActivity就是繼承自io.flutter.embedding.android.FlutterActivity,該類展示的是一個全屏的Flutter UI,它的主要作用是:
- 顯示Android的啟動影片
- 下手Flutter的啟動影片
- 配置狀態欄
- 選擇Dart執行應用程式包路徑入口點(默認是main()),選擇Flutter的初始路由
- 保存和回復實體狀態
首先我們來看類宣告部分
public class FlutterActivity extends Activity
implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
FlutterActivityAndFragmentDelegate.Host分析
根據繼承關系可以發現,FlutterActivity直接繼承于Activity,同時實作了FlutterActivityAndFrameDelegate.Host,LifecycleOwner介面,Activity和LifecycleOwner不做解釋,我們來看FlutterActivityAndFragmentDelegate.Host介面
class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
/**
* 擴展四個介面
* SplashScreenProvider,提供一個 SplashScreen 以在 Flutter 初始化和渲染其第一幀時顯示
* FlutterEngineProvider,提供和創建FlutterEngine
* FlutterEngineConfigurator,在創建 FlutterEngine 后配置它,例如,添加插件
* PlatformPlugin.PlatformPluginDelegate,PlatformPlugin 通常為 Flutter 框架請求的平臺功能實作了默認行為,允許實作者自定義 Flutter 框架呼叫彈出 Android 端導航堆疊時所需的行為,
*/
interface Host
extends SplashScreenProvider,
FlutterEngineProvider,
FlutterEngineConfigurator,
PlatformPlugin.PlatformPluginDelegate {
@NonNull
Context getContext();
// 是否從intent獲取路由
@Nullable
boolean shouldHandleDeeplinking();
@Nullable
Activity getActivity();
// 獲取Activity或者Fragment的Lifecycle
@NonNull
Lifecycle getLifecycle();
// 獲取宿主啟動Flutter攜帶的引數,通過intent決議,譬如enable-dart-profiling等,
@NonNull
FlutterShellArgs getFlutterShellArgs();
// 獲取靜態快取的EngineId,如果沒有就回傳空,通過intent的cached_engine_id引數傳遞,
@Nullable
String getCachedEngineId();
// 引擎是否跟宿主一起destory
boolean shouldDestroyEngineWithHost();
// detach flutter engine
void detachFromFlutterEngine();
// 獲取dart主入口,默認main,
@NonNull
String getDartEntrypointFunctionName();
// 回傳app bundle dart代碼存在的路徑
@NonNull
String getAppBundlePath();
// 獲取初始路由地址,
// 默認先從intent中決議route的值,沒有就去meta-data決議io.flutter.InitialRoute的值,沒有就回傳null,
@Nullable
String getInitialRoute();
// 獲取Flutter的渲染模式,詳情見“[Flutter實踐深入分析中——FlutterView相關原始碼分析](https://beason.blog.csdn.net/article/details/120929369)”
@NonNull
RenderMode getRenderMode();
// 獲取Transparency模式,用在FlutterView呈現FlutterEngine引擎渲染效果
@NonNull
TransparencyMode getTransparencyMode();
// 提供一個Flutter開屏圖片,
@Nullable
SplashScreen provideSplashScreen();
// 回傳一個用來渲染FlutterView的FlutterEngine引擎
@Nullable
FlutterEngine provideFlutterEngine(@NonNull Context context);
// 創建和配置platform plugin,
@Nullable
PlatformPlugin providePlatformPlugin(
@Nullable Activity activity, @NonNull FlutterEngine flutterEngine);
// 根據需要配置FLutterEngine
void configureFlutterEngine(@NonNull FlutterEngine flutterEngine);
// 周期detached之前清除FlutterEngine配置
void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine);
// 如果 FlutterEngine 的插件系統已經連接到Activity,則回傳 true,允許插件與其互動
boolean shouldAttachEngineToActivity();
void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView);
void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView);
// Flutter UI開始繪制時呼叫
void onFlutterUiDisplayed();
// Flutter停止繪制時呼叫
void onFlutterUiNoLongerDisplayed();
// 恢復狀態
boolean shouldRestoreAndSaveState();
}
}
根據上面的原始碼分析可以知道FlutterActivityAndFragmentDelegate.Host提供的一系列相關引擎宣告周期、Flutter UI繪制周期、插件相關周期等方法可以知道,它是一個中間層,它是Flutter與Activity/Fragment之間的一個介面約定,而宿主Activity/Fragment幾乎不直接參加與Flutter之間的互動,這樣做的好處有:
- 利于解耦,Flutter/Fragment不直接與Flutter互動,利于維護
- Flutter版本迭代快,利于專案后期Flutter SDK的升級,而不必修改任何原生代碼
- 代碼的重復利用,后面會介紹Fragment和FlutterFragmentActivity,大部分都是復用了FlutterActivityAndFragmentDelegate內部相關邏輯
下面我們再來看看FlutterActivity的onCreate方法
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
switchLaunchThemeForNormalTheme();
super.onCreate(savedInstanceState);
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(this);
delegate.onRestoreInstanceState(savedInstanceState);
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
configureWindowForTransparency();
setContentView(createFlutterView());
configureStatusBarForFullscreenFlutterExperience();
}
詳細的介紹之前的文章有介紹這里不再詳述,見:Flutter時間深入分析之——Flutter APP啟動流程分析
FlutterActivityAndFragmentDelegate分析
從上面分析我們知道FlutterActivityAndFragmentDelegate.Host宣告了大量的Activity/Fragment與Flutter平臺通信的介面,那么FlutterActivityAndFragmentDelegate根據名字我們大概判斷它就是Activity/Fragment的一個代理類,也是直接與Activity/Fragment進行互動的類,
下面一個個來分析FlutterActivityAndFragmentDelegate的核心方法
onAttach方法
onAttach方法在Activity的onCreate方法和Fragment的onAttach方法中被呼叫,核心原始碼:
void onAttach(@NonNull Context context) {
// 確保delegate沒有被release
ensureAlive();
if (flutterEngine == null) {
setupFlutterEngine();
}
if (host.shouldAttachEngineToActivity()) {
flutterEngine.getActivityControlSurface().attachToActivity(this, host.getLifecycle());
}
platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
host.configureFlutterEngine(flutterEngine);
}
從上面的代碼分析,attach方法主要職責:
- 初始化Flutter系統,確保delegate沒有被release
- 獲取(根據EngineID獲取,目前還未正式使用)或者創建FlutterEngine
- 平臺插件獲取和自定義插件的注冊
- 引擎配置,
onStart方法
onStart方法在Activity和Fragment的onStart方法被呼叫,核心原始碼:
// Activity和Fragment的onStart方法被呼叫,開始執行Dart 代碼的入口(Dart代碼如果沒有執行的情況下)
void onStart() {
Log.v(TAG, "onStart()");
ensureAlive();
doInitialFlutterViewRun();
}
/**
* 首次在FlutterView中執行Dart代碼
* 不支持在給定的FlutterView中重新加載、重啟Dart,如果Dart已經運行,那么什么都不做
*/
private void doInitialFlutterViewRun() {
if (host.getCachedEngineId() != null) {
return;
}
if (flutterEngine.getDartExecutor().isExecutingDart()) {
return;
}
// 各種優先級獲取初始跳轉dart的路由地址,
String initialRoute = host.getInitialRoute();
if (initialRoute == null) {
initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
if (initialRoute == null) {
initialRoute = DEFAULT_INITIAL_ROUTE;
}
}
// 通過引擎的NavigationChannel設定初始路由資訊,
flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
//按照優先級獲取appBundlePath,默認從host獲取,無則從FlutterLoader獲取,
String appBundlePathOverride = host.getAppBundlePath();
if (appBundlePathOverride == null || appBundlePathOverride.isEmpty()) {
appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
}
// 配置dart的entrypoint并且執行,默認入口函式名為main,可通過meta-data的io.flutter.Entrypoint修改,
DartExecutor.DartEntrypoint entrypoint =
new DartExecutor.DartEntrypoint(
appBundlePathOverride, host.getDartEntrypointFunctionName());
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
}
onCreateView方法
看完上面的邏輯,引擎,插件,環境都已經準備妥當,接下來就是創建View,onCreateView見名知意,大概職責如下:
- 在 View 層次結構中創建一個新的 FlutterView
- 添加一個 FlutterUiDisplayListener
- 將 FlutterEngine 附加到新的 FlutterView
- 回傳新的視圖層次結構
我們來看看onCreateView方法:
@NonNull
View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// 確保 delegate沒有吧release
ensureAlive();
// 根據不同的渲染模式選擇不同的View(SurfaceView或者TextureView)
if (host.getRenderMode() == RenderMode.surface) {
FlutterSurfaceView flutterSurfaceView =
new FlutterSurfaceView(
host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
// 創建FLutterView包含FlutterSurfaceView
host.onFlutterSurfaceViewCreated(flutterSurfaceView);
flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
} else {
FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
// 創建FLutterView包含FlutterTextureView
host.onFlutterTextureViewCreated(flutterTextureView);
flutterView = new FlutterView(host.getActivity(), flutterTextureView);
}
// 添加監聽,當flutter渲染首幀時回呼,當 Flutter 開始和停止將像素渲染到 Android 視圖層次結構時呼叫的偵聽器,
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
// 創建一個FlutterSplashView開屏view
flutterSplashView = new FlutterSplashView(host.getContext());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
flutterSplashView.setId(View.generateViewId());
} else {
flutterSplashView.setId(486947586);
}
// 顯示開屏圖示,即io.flutter.embedding.android.SplashScreenDrawable配置的drawable圖
flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
// FlutterView與flutterEngine關聯attach,
flutterView.attachToFlutterEngine(flutterEngine);
// 回傳被開屏view包裹的FlutterView,
return flutterSplashView;
}
//回呼監聽定義,回呼中本質是觸發呼叫對應FlutterActivity或FlutterFragment的FlutterActivityAndFragmentDelegate.Host實作方法,
@NonNull
private final FlutterUiDisplayListener flutterUiDisplayListener =
new FlutterUiDisplayListener() {
@Override
public void onFlutterUiDisplayed() {
//本質在FlutterActivity中呼叫Activity 5.0以上的reportFullyDrawn()安卓官方方法,
host.onFlutterUiDisplayed();
}
@Override
public void onFlutterUiNoLongerDisplayed() {
//本質在FlutterActivity中呼叫,默認空實作,
host.onFlutterUiNoLongerDisplayed();
}
};
到這里我們FlutterActivityAndFragmentDelegate的核心代碼基本上介紹完畢
從上面代碼分析結果看onCreateView的職責和邏輯都比較清晰,但是唯一有個疑問就是為什么最后回傳的不是FLutterView而是回傳的一個包含FLutterView的FlutterSplashView,下面我們再一起來分析下FlutterSplashView,看看是如何處理FlutterSplashView和FlutterView之間的關系,
FlutterSplashView分析
FlutterSplashView按照字面理解它的主要作用就是顯示 SplashScreen 的視圖,直到給定的 FlutterView 呈現其第一幀,
我們來看看它的核心流程:
final class FlutterSplashView extends FrameLayout {
// 當 FlutterEngine 附加到給定 FlutterView 或從給定 FlutterView 分離時收到通知的偵聽器,
@NonNull
private final FlutterView.FlutterEngineAttachmentListener flutterEngineAttachmentListener = ...
// 當 Flutter 開始和停止將像素渲染到 Android 視圖層次結構時呼叫的偵聽器,
@NonNull
private final FlutterUiDisplayListener flutterUiDisplayListener = ...
// 將啟影片面轉換為 Flutter UI
@NonNull
private final Runnable onTransitionComplete =
new Runnable() {
@Override
public void run() {
removeView(splashScreenView);
previousCompletedSplashIsolate = transitioningIsolateId;
}
};
/**
* 把給定的splashScreen顯示在flutterView之上,直到flutterView的首幀渲染出來才過渡消失
*/
public void displayFlutterViewWithSplash(
@NonNull FlutterView flutterView, @Nullable SplashScreen splashScreen) {
// 如果上一個FlutterView顯示中,先洗掉.
if (this.flutterView != null) {
this.flutterView.removeOnFirstFrameRenderedListener(flutterUiDisplayListener);
removeView(this.flutterView);
}
// 復位
if (splashScreenView != null) {
removeView(splashScreenView);
}
// 把flutterView添加給當前FlutterSplashView,本質是一個FrameLayout,
this.flutterView = flutterView;
addView(flutterView);
this.splashScreen = splashScreen;
// 顯示一個splash screen開屏圖,
if (splashScreen != null) {
//如果flutterView未渲染出來則條件成立,
if (isSplashScreenNeededNow()) {
splashScreenView = splashScreen.createSplashView(getContext(), splashScreenState);
addView(this.splashScreenView);
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
} else if (isSplashScreenTransitionNeededNow()) {
splashScreenView = splashScreen.createSplashView(getContext(), splashScreenState);
addView(splashScreenView);
transitionToFlutter();
} else if (!flutterView.isAttachedToFlutterEngine()) {
flutterView.addFlutterEngineAttachmentListener(flutterEngineAttachmentListener);
}
}
}
/**
* 如果啟影片面正在過渡到 Flutter 體驗,則回傳 true
*/
private boolean wasPreviousSplashTransitionInterrupted() {
return flutterView.hasRenderedFirstFrame() && !hasSplashCompleted();
}
/**
* 如果特定 Flutter 體驗的啟動 UI 已經完成,則回傳 true,
*/
private boolean hasSplashCompleted() {
return flutterView.getAttachedFlutterEngine().getDartExecutor().getIsolateServiceId() != null
&& flutterView
.getAttachedFlutterEngine()
.getDartExecutor()
.getIsolateServiceId()
.equals(previousCompletedSplashIsolate);
}
/**
* 開屏過渡到flutterview顯示
*/
private void transitionToFlutter() {
transitioningIsolateId =
flutterView.getAttachedFlutterEngine().getDartExecutor().getIsolateServiceId();
splashScreen.transitionToFlutter(onTransitionComplete);
}
}
從上面的代碼分析,FlutterSplashView邏輯并不復雜,主要就是在FlutterUI第一幀渲染之前顯示默認的Drawable,等到Flutter UI第一幀繪制的時候再remove掉,內部的實作邏輯都比較簡單這里不再介紹,下面繼續
FlutterFragment分析
上面分析完FlutterActivity的流程,我們再來看FlutterFragment就比較簡單了,
我們在使用FlutterFragment的時候,如果宿主Actvity而不是FlutterFragmentActivity的話,需要我們手動關聯一下方法,這些方法都被添加了@ActvivityCallThrough注釋宣告,如:
- onPostResume()
- onBackPressed()
- onRequestPermissionsResult(int, String[], int[]) ()}
- onNewIntent(Intent) ()}
- onUserLeaveHint()
- onTrimMemory(int)
此外,當為此 Fragment 的startActivityForResult 時,請務必呼叫 Fragment.startActivityForResult(Intent, int) 而不是 Activity.startActivityForResult(Intent, int),如果呼叫了該方法的 Activity 版本,則此 Fragment 將永遠不會收到其 Fragment.onActivityResult(int, int, Intent) 回呼,如果方便,可以考慮使用 FlutterActivity 而不是 FlutterFragment 來避免轉發呼叫的作業,
下面看核心原始碼
//FlutterFragment也實作了前面分析的FlutterActivityAndFragmentDelegate.Host介面,
public class FlutterFragment extends Fragment
implements FlutterActivityAndFragmentDelegate.Host, ComponentCallbacks2 {
......
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
//FlutterActivity的區別在于FlutterFragment在他自己的onAttach中實體化FlutterActivityAndFragmentDelegate并呼叫onAttach方法,
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(context);
}
@Nullable
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//FlutterActivity類似,只不過是在FlutterFragment對應生命周期回呼,
return delegate.onCreateView(inflater, container, savedInstanceState);
}
......
//與FlutterActivity類似,只是這個方法不是Fragment自己框架回呼,需要依賴在Activity中呼叫,
//譬如FlutterFragmentActivity中對應同名方法的實作,
//注意這里的@ActivityCallThrough注解就是這個含義,
@ActivityCallThrough
public void onPostResume() {
delegate.onPostResume();
}
......
}
其實我們掌握了FlutterActivity之后,FlutterFragment核心基本上沒啥區別,主要都是通過代理FlutterActivityAndFragmentDelegate與Flutter平臺打交道,實作UI的展示,不做細說,下面繼續
FlutterFragmentActivity分析
從上面的FlutterFragment可以看到,FlutterFragmentActivity可以說是FlutterFragment的一個宿主Activity,給我們自己使用Activity系結FlutterFragment做了很好的參考,其內部與Flutter平臺的關聯關系都已經處理,用戶不需要再考慮上面的各種關聯方法的關聯,
FlutterFragmentActivity是一個基于 FragmentActivity 的 Flutter Activity,
FlutterFragmentActivity 的存在是因為生態系統中有一些 Android API 只接受一個 FragmentActivity, 如果不需要 FragmentActivity,則應考慮使用常規 FlutterActivity 代替,
我們繼續看FlutterFragmentActivity核心方法
onCreate方法
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 這里和FlutterActivity完全一樣,只是不用實體化一個FlutterActivityAndFragmentDelegate,因為其內部的FlutterFragment會做這些事
switchLaunchThemeForNormalTheme();
super.onCreate(savedInstanceState);
configureWindowForTransparency();
// 呼叫createFragmentContainer生成了一個View設定給Activity的content,用于展示FlutterFragment,接下來會創建FLutterFragment
setContentView(createFragmentContainer());
configureStatusBarForFullscreenFlutterExperience();
//檢驗的是FlutterFragment是否添加OK,如果沒有就創建FlutterFragment并commit
ensureFlutterFragmentCreated();
}
需要關聯的方法呼叫
@Override
public void onPostResume() {
super.onPostResume();
flutterFragment.onPostResume();
}
@Override
protected void onNewIntent(@NonNull Intent intent) {
flutterFragment.onNewIntent(intent);
super.onNewIntent(intent);
}
@Override
public void onBackPressed() {
flutterFragment.onBackPressed();
}
注意上面FlutterFragment一端,提示的需要手動關聯的,在這里只是舉出了一部分;對于需要關聯或者我們自己使用Activity集成FlutterFragment的情形,這個FlutterFragmentActivity是個很好的參考實作,
總結
上面我們通過對FlutterActivity和FlutterFragment的了解,相信對Flutter UI如何被顯示到Android的Activity和Fragment有了一定的認識,Android原生控制元件只是作為一個容器,FlutterView才是真正展示FlutterUI的地方,
但是FlutterView的使用又不能跟普通原生View一樣使用,如果我們需要在自己的原生View里面直接嵌套FlutterView,就要在宿主類(Activity或者Fragment)中同樣類似FlutterActivity或者FlutterFragment一樣,通過delegate手動去實作各種引擎,FlutterUI的生命周期系結處理,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/337741.html
標籤:其他
上一篇:View的幾個小工具
