Flutter源碼分析之初始化篇一(android)

前言

回想在公司工做拿到的第一個項目是一個flash遊戲項目,在那個時候flash遊戲很是流行,尚未被html5取代的跡象。遊戲程序架構採用的是後端mfc+前端flash框架,整個項目代碼20萬行,就我本身一我的開發。公司的要求是能修改、增長遊戲的功能。當時我雖然有一點mfc的基礎,可是遊戲沒有接觸過、flash的actionscript3更是一竅不通。那怎麼辦呢?學唄。因而通過一兩個月的各類畫uml圖、流程圖、寫僞代碼等等一系列的理解學習,發現不但理解了後端、前端的工做原理,甚至能夠開始擼框架了。那個時候整天跟人吹牛,如今想起來仍是以爲十分的有趣。一個看似龐大的體系從一竅不通到完全掌握,這個過程只要經歷一遍,以後就以爲沒有什麼問題是解決不了的。html

flutter在實現上破天荒的沒有采用目前的各類成熟視圖體系,而是採用了本身構建一套視圖體系,用gpu加速,因此性能高、界面流暢。對此,表示十分的感興趣。那麼要完全的挖掘一個框架的本質,就只有研究源碼這麼一條道路。從今天起,預計花一到兩個月的時間來分析flutter的源碼,在這裏給你們分享下研究的過程。前端

這一系列的文章應該會很是長,研究源碼須要耐心,不是麼。html5

文章結構

筆者認爲這樣android

  • 分析代碼
  • 提出這段代碼問題,應該在後續的分析中解決
  • 解決問題,分析前面的問題哪些是解決的
  • 總結代碼
  • 在階段性分析後給出圖

flutter源碼分析之FlutterActivity

實現接口分析

/// activity實現了三個接口
public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory {

/// 視圖提供類,一個方法getFlutterView
public interface Provider {
    FlutterView getFlutterView();
}

/// 插件註冊
public interface PluginRegistry {
    /// 註冊一個插件
    PluginRegistry.Registrar registrarFor(String var1);
    /// 是否有這個插件
    boolean hasPlugin(String var1);
    /// 插件發佈值
    <T> T valuePublishedByPlugin(String var1);
    /// 下面開始爲插件生命週期回調
    public interface PluginRegistrantCallback {
        void registerWith(PluginRegistry var1);
    }

    /// 顯然是視圖銷燬的回調
    public interface ViewDestroyListener {
        boolean onViewDestroy(FlutterNativeView var1);
    }
        
    //// 不知道幹啥,先留着
    public interface UserLeaveHintListener {
        void onUserLeaveHint();
    }
   
    //// activity生命週期回調之onNewIntent
    public interface NewIntentListener {
        boolean onNewIntent(Intent var1);
    }
    
  //// activity生命週期回調之onActivityResult
    public interface ActivityResultListener {
        boolean onActivityResult(int var1, int var2, Intent var3);
    }

//// activity生命週期回調之onRequestPermissionsResult
    public interface RequestPermissionsResultListener {
        boolean onRequestPermissionsResult(int var1, String[] var2, int[] var3);
    }
    /// 插件的註冊者,至關於插件的宿主。
    public interface Registrar {
        Activity activity();

        Context context();

        Context activeContext();
        /// 這個BinaryMessager還不知道幹啥
        BinaryMessenger messenger();
        /// TextureRegistry不清楚
        TextureRegistry textures();
        /// 獲取視圖
        FlutterView view();
        /// 尋找資源
        String lookupKeyForAsset(String var1);
        /// 尋找資源
        String lookupKeyForAsset(String var1, String var2);
        /// 發佈值,與上面的valuePublishedByPlugin對應
        PluginRegistry.Registrar publish(Object var1);
        
        /// 增長生命週期回調
        PluginRegistry.Registrar addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener var1);

        /// 增長生命週期回調
        PluginRegistry.Registrar addActivityResultListener(PluginRegistry.ActivityResultListener var1);

        PluginRegistry.Registrar addNewIntentListener(PluginRegistry.NewIntentListener var1);

        /// 增長生命週期回調
        PluginRegistry.Registrar addUserLeaveHintListener(PluginRegistry.UserLeaveHintListener var1);
        
        /// 增長生命週期回調
        PluginRegistry.Registrar addViewDestroyListener(PluginRegistry.ViewDestroyListener var1);
    }
}

/// 視圖工廠
  public interface ViewFactory {
        /// 建立flutterView
        FlutterView createFlutterView(Context var1);
        //// 建立nativeview
        FlutterNativeView createFlutterNativeView();
        ///  暫時搞不清楚幹啥的,先留着
        boolean retainFlutterNativeView();
    }

問題

  • (1)FlutterNativeView和FlutterView有啥區別和聯繫
  • (2)UserLeaveHintListener做用?
  • (3)ViewFactory#retainFlutterNativeView做用?
  • (4)BinaryMessenger做用
  • (5)TextureRegistry做用

這些問題在以後的分析中應該能解決。shell

Activity的生命週期分析

構造函數

///建立FlutterActivityDelegate
 private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
    private final FlutterActivityEvents eventDelegate;
    private final Provider viewProvider;
    private final PluginRegistry pluginRegistry;

    public FlutterActivity() {
    /// FlutterActivityDelegate實現了這三個接口,並賦值給三個變量,這樣調用起來更加清晰。
        this.eventDelegate = this.delegate;
        this.viewProvider = this.delegate;
        this.pluginRegistry = this.delegate;
    }

onCreate、onResume、onStop、onDestory、onPause、onNewIntent、onStart、onActivityResult、onRequestPermissionResult

///這裏都是由建立FlutterActivityDelegate代理執行,就不一一貼出來了
protected void onXXX() {
        super.onXXX();
        this.eventDelegate.onXXX();
    }

建立FlutterView

值得注意的是這裏的三個回調,表示FlutterView是如何建立出來的。後端

public FlutterView getFlutterView() {
  /// 有關的函數,只有這個由FlutterActivityDelegate代理執行
        return this.viewProvider.getFlutterView();
    }

    public FlutterView createFlutterView(Context context) {
        return null;
    }

    public FlutterNativeView createFlutterNativeView() {
        return null;
    }

    public boolean retainFlutterNativeView() {
        return false;
    }

FlutterActivity總結

  • FlutterActivity的生命週期和各個方法實際上由FlutterActivityDelegate代理執行。
  • 從Activity的源碼來看,已經清晰的看出FlutterActivity解決了生命週期的回調,插件管理,建立FlutterView以及相關的ui。

問題

  • (6)FlutterView究竟如何建立的
  • (7)retainFlutterNativeView有什麼做用

flutter源碼分析之FlutterActivityDelegate

仍是onCreate

/// 啓動參數解析
String[] args = getArgsFromIntent(this.activity.getIntent());
/// 等待並保證初始化完成
FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
/// 建立flutterView,注意到上面默認的返回null
        this.flutterView = this.viewFactory.createFlutterView(this.activity);
        if (this.flutterView == null) {
        /// 默認走這裏,createFlutterNativeView默認返回null
            FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
            //實際建立了FlutterView
            this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
            // 設置layout,並添加到當前activity,做爲主視圖
            this.flutterView.setLayoutParams(matchParent);
            this.activity.setContentView(this.flutterView);
            //建立啓動ui
            this.launchView = this.createLaunchView();
            if (this.launchView != null) {
               //若是有建立啓動ui成功,那麼增長到當前activity上面
                this.addLaunchView();
            }
        }

看下FlutterMain.ensureInitializationComplete緩存

public static void ensureInitializationComplete(Context applicationContext, String[] args) {
         // 保證ui線程運行
        if (Looper.myLooper() != Looper.getMainLooper()) {
            throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
        } else if (!sInitialized) {
            try {
               // 等待完成,這裏有個疑問點,sResourceExtractor是何時建立的
                sResourceExtractor.waitForCompletion();
                
                // 繼續解析參數
                List<String> shellArgs = new ArrayList();
                shellArgs.add("--icu-data-file-path=" + new File(PathUtils.getDataDirectory(applicationContext), "icudtl.dat"));
                if (args != null) {
                    Collections.addAll(shellArgs, args);
                }

                if (sIsPrecompiledAsSharedLibrary) {
                    shellArgs.add("--aot-shared-library-path=" + new File(PathUtils.getDataDirectory(applicationContext), sAotSharedLibraryPath));
                } else {
                    if (sIsPrecompiledAsBlobs) {
                        shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext));
                    } else {
                        shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext));
                        shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext) + "/" + sFlutterAssetsDir);
                    }

                    shellArgs.add("--vm-snapshot-data=" + sAotVmSnapshotData);
                    shellArgs.add("--vm-snapshot-instr=" + sAotVmSnapshotInstr);
                    shellArgs.add("--isolate-snapshot-data=" + sAotIsolateSnapshotData);
                    shellArgs.add("--isolate-snapshot-instr=" + sAotIsolateSnapshotInstr);
                }

                if (sSettings.getLogTag() != null) {
                    shellArgs.add("--log-tag=" + sSettings.getLogTag());
                }
                
                // 查找bundle
                String appBundlePath = findAppBundlePath(applicationContext);
                // native初始化,參數爲解析的全部啓動參數和一個bundle的路徑
                nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath);
                sInitialized = true;
            } catch (Exception var4) {
                Log.e("FlutterMain", "Flutter initialization failed.", var4);
                throw new RuntimeException(var4);
            }
        }
    }
///這裏的nativeInit是jni調用,實際做用是? 這裏我猜是初始化dart環境,並初始化加載bundle,相似初始化js環境,並加載jsbundle
  private static native void nativeInit(Context var0, String[] var1, String var2);

看下:架構

sResourceExtractor.waitForCompletion();

sResourceExtractor是啥時候建立的?那麼這裏全局搜索了一番,瞭解到到FlutterMain#startInitialization這個方法是在FlutterApplication中調用的,因此先看下Application。這裏先提出疑問,以後解決。app

問題

  • (8)sResourceExtractor.waitForCompletion();在幹什麼?
  • (9)new FlutterView(this.activity, (AttributeSet)null, nativeView);這裏是否能夠解釋前面的問題(1)
  • (10) nativeInit做用?bundle是什麼,如何加載?

flutter源碼分析之FlutterApplication

原本這個Application應該是第一個分析的,可是首先用戶看到的flutter建立的example裏面暴露的第一個類應該就是FlutterActivity。FlutterApplication是在AndroidManifest中定義的,因此筆者一開始沒有注意到,這裏插個隊補上。框架

public class FlutterApplication extends Application {
    private Activity mCurrentActivity = null;

    public FlutterApplication() {
    }

    // 顯然這裏進行了全局初始化
    @CallSuper
    public void onCreate() {
        super.onCreate();
        FlutterMain.startInitialization(this);
    }

    public Activity getCurrentActivity() {
        return this.mCurrentActivity;
    }
    
    // 設置當前的Activity
    public void setCurrentActivity(Activity mCurrentActivity) {
        this.mCurrentActivity = mCurrentActivity;
    }
}

FlutterMain.startInitialization

public static void startInitialization(Context applicationContext, FlutterMain.Settings settings) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            throw new IllegalStateException("startInitialization must be called on the main thread");
        } else if (sSettings == null) {
            sSettings = settings;
            long initStartTimestampMillis = SystemClock.uptimeMillis();
            initConfig(applicationContext);
            initAot(applicationContext);
            initResources(applicationContext);
            System.loadLibrary("flutter");
            long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
            nativeRecordStartTimestamp(initTimeMillis);
        }
    }

Setting

這裏的Setting很是簡單,只是提供了日誌的tag,那麼這個logTag在哪裏用?又是一個疑問。

public static class Settings {
        private String logTag;

        public Settings() {
        }

        public String getLogTag() {
            return this.logTag;
        }

        public void setLogTag(String tag) {
            this.logTag = tag;
        }
    }

initConfig

initConfig,這個函數主要用於初始化配置

private static void initConfig(Context applicationContext) {
        try {
            Bundle metadata = applicationContext.getPackageManager().getApplicationInfo(applicationContext.getPackageName(), 128).metaData;
            if (metadata != null) {
                sAotSharedLibraryPath = metadata.getString(PUBLIC_AOT_AOT_SHARED_LIBRARY_PATH, "app.so");
                sAotVmSnapshotData = metadata.getString(PUBLIC_AOT_VM_SNAPSHOT_DATA_KEY, "vm_snapshot_data");
                sAotVmSnapshotInstr = metadata.getString(PUBLIC_AOT_VM_SNAPSHOT_INSTR_KEY, "vm_snapshot_instr");
                sAotIsolateSnapshotData = metadata.getString(PUBLIC_AOT_ISOLATE_SNAPSHOT_DATA_KEY, "isolate_snapshot_data");
                sAotIsolateSnapshotInstr = metadata.getString(PUBLIC_AOT_ISOLATE_SNAPSHOT_INSTR_KEY, "isolate_snapshot_instr");
                sFlx = metadata.getString(PUBLIC_FLX_KEY, "app.flx");
                sSnapshotBlob = metadata.getString(PUBLIC_SNAPSHOT_BLOB_KEY, "snapshot_blob.bin");
                sFlutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, "flutter_assets");
            }

        } catch (NameNotFoundException var2) {
            throw new RuntimeException(var2);
        }
    }

這裏能夠看到flutter的定製選項,能夠在androd的meta裏面定義

  • sAotSharedLibraryPath
  • sAotVmSnapshotData
  • sAotVmSnapshotInstr
  • sAotIsolateSnapshotData
  • sAotIsolateSnapshotInstr
  • sFlx
  • sSnapshotBlob
  • sFlutterAssetsDir

initAot

關於aot,這裏有幾篇博文介紹:
https://www.cnblogs.com/zengm...
https://www.cnblogs.com/tinyt...

AOT是一種靜態編譯技術,與JIT對應

private static void initAot(Context applicationContext) {
        // 列出全部的assets文件夾中的資源
        Set<String> assets = listRootAssets(applicationContext);
        // 
        sIsPrecompiledAsBlobs = assets.containsAll(Arrays.asList(sAotVmSnapshotData, sAotVmSnapshotInstr, sAotIsolateSnapshotData, sAotIsolateSnapshotInstr));
        sIsPrecompiledAsSharedLibrary = assets.contains(sAotSharedLibraryPath);
        // 意思是兩個不能同時存在?
        if (sIsPrecompiledAsBlobs && sIsPrecompiledAsSharedLibrary) {
            throw new RuntimeException("Found precompiled app as shared library and as Dart VM snapshots.");
        }
    }

initResources

private static void initResources(Context applicationContext) {
         // 開始清理資源
        (new ResourceCleaner(applicationContext)).start();
        
        // 建立sResourceExtractor
        sResourceExtractor = (new ResourceExtractor(applicationContext)).addResources(SKY_RESOURCES).addResource(fromFlutterAssets(sFlx)).addResource(fromFlutterAssets(sSnapshotBlob)).addResource(fromFlutterAssets(sAotVmSnapshotData)).addResource(fromFlutterAssets(sAotVmSnapshotInstr)).addResource(fromFlutterAssets(sAotIsolateSnapshotData)).addResource(fromFlutterAssets(sAotIsolateSnapshotInstr)).addResource(fromFlutterAssets("kernel_blob.bin")).addResource(fromFlutterAssets("platform.dill"));
        
        // 增長資源
        if (sIsPrecompiledAsSharedLibrary) {
            sResourceExtractor.addResource(sAotSharedLibraryPath);
        } else {
            sResourceExtractor.addResource(sAotVmSnapshotData).addResource(sAotVmSnapshotInstr).addResource(sAotIsolateSnapshotData).addResource(sAotIsolateSnapshotInstr).addResource(sSnapshotBlob);
        }
        //開始
        sResourceExtractor.start();
    }

看下:
(new ResourceCleaner(applicationContext)).start(),做用是清理緩存

boolean result = name.startsWith(".org.chromium.Chromium.");
                    return result;
 ...
  protected Void doInBackground(Void... unused) {
              File[] var2 = this.mFilesToDelete;
            int var3 = var2.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                File file = var2[var4];
                if (file.exists()) {
                    this.deleteRecursively(file);
                }
            }
}

看下:sResourceExtractor.start();

ResourceExtractor start() {
        assert this.mExtractTask == null;

        this.mExtractTask = new ResourceExtractor.ExtractTask();
        this.mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Void[0]);
        return this;
    }
...
 private void extractResources() {
  File dataDir = new File(PathUtils.getDataDirectory(ResourceExtractor.this.mContext));
 ...
 InputStream is = manager.open(asset);
 Throwable var9 = null;

try {
  OutputStream os = new FileOutputStream(output);
 Throwable var11 = null;
...
  while((count = is.read(buffer, 0, 16384)) != -1) {
       os.write(buffer, 0, count);
  }
...
}
...
public final class PathUtils {
    ...
    public static String getDataDirectory(Context applicationContext) {
        return applicationContext.getDir("Lflutter", 0).getPath();
    }
    ...
}

這段代碼是將指定的assert文件夾中的文件拷貝到應用程序目錄中的flutter文件夾下,說明後續程序須要直接使用文件,而不是assert文件夾中的二進制。

native部分

System.loadLibrary("flutter");
nativeRecordStartTimestamp(initTimeMillis);

初始化native,並記錄時間,native的部分,這篇文章先不予考慮,專門在一個專題裏面寫。

問題

此次光看代碼比較難以理解,須要動態調試了

  • (11)sIsPrecompiledAsBlobs && sIsPrecompiledAsSharedLibrary這兩個參數具體表明什麼含義,爲何不能同時存在?和flutter的hotload有關嗎,和flutter是調試版本仍是發佈版本有關嗎?
  • (12)flutter中的so庫具體有哪些,有什麼做用?

解決問題

  • (8)sResourceExtractor.waitForCompletion();在幹什麼?

此次顯然已經解決了前面的問題(8), FlutterActivity在啓動的時候,須要等待FlutterApplicaiton中的異步加載資源完畢

總結

FlutterApplication在onCreate的時候,初始化加載Flutter中的資源,含bundle、so庫等重要啓動資源,而在FlutterActivity的onCreate中,會等待FlutterApplication的這個過程完畢以後再進行下一步的初始化。

Flutter源碼分析建立FlutterView

這裏接着上面來分析FlutterView的建立過程:

public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry, AccessibilityStateChangeListener {

注意到FlutterView繼承了SurfaceView,關於SurfaceView,能夠參考幾篇博文理解:

https://blog.csdn.net/android...
https://www.cnblogs.com/zhang...

SurfaceView使用的繪圖線程不是ui線程,咱們平時使用的攝像頭、遊戲之類的要求圖形性能比較高的場景就靠它了。

看下構造函數:

this.nextTextureId = new AtomicLong(0L);
...
@Override
    public TextureRegistry.SurfaceTextureEntry createSurfaceTexture() {
        final SurfaceTexture surfaceTexture = new SurfaceTexture(0);
        surfaceTexture.detachFromGLContext();
        final SurfaceTextureRegistryEntry entry =
                new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture);
        nativeRegisterTexture(mNativeView.get(), entry.id(), surfaceTexture);
        return entry;
    }

這裏使用到了SurfaceTexture,並執行了nativeRegisterTexture,關於SurfaceTexture,找到這麼幾篇博文:

https://www.cnblogs.com/wytig...
https://blog.csdn.net/hejjunl...
https://blog.csdn.net/u010949...
https://blog.csdn.net/tq08g2z...
https://blog.csdn.net/OnafioO...
https://blog.csdn.net/u010949...
https://blog.csdn.net/u010949...

基本上全是csdn的老文章!

這個SurfactTexture具體做用?先放放。

接着往下看:

this.mIsSoftwareRenderingEnabled = nativeGetIsSoftwareRenderingEnabled();

關於android的軟件渲染仍是硬件渲染:
https://blog.csdn.net/wlwl007...
https://blog.csdn.net/luoshen...
http://www.sohu.com/a/1605251...

繼續

this.mMetrics = new FlutterView.ViewportMetrics();
this.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
...
 private void updateViewportMetrics() {
        if (this.isAttached()) {
            nativeSetViewportMetrics(this.mNativeView.get(), this.mMetrics.devicePixelRatio, this.mMetrics.physicalWidth, this.mMetrics.physicalHeight, this.mMetrics.physicalPaddingTop, this.mMetrics.physicalPaddingRight, this.mMetrics.physicalPaddingBottom, this.mMetrics.physicalPaddingLeft, this.mMetrics.physicalViewInsetTop, this.mMetrics.physicalViewInsetRight, this.mMetrics.physicalViewInsetBottom, this.mMetrics.physicalViewInsetLeft);
            WindowManager wm = (WindowManager)this.getContext().getSystemService("window");
            float fps = wm.getDefaultDisplay().getRefreshRate();
            VsyncWaiter.refreshPeriodNanos = (long)(1.0E9D / (double)fps);
        }
    }
...
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        this.mMetrics.physicalWidth = width;
        this.mMetrics.physicalHeight = height;
        this.updateViewportMetrics();
        super.onSizeChanged(width, height, oldWidth, oldHeight);
    }

    public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
        this.mMetrics.physicalPaddingTop = insets.getSystemWindowInsetTop();
        this.mMetrics.physicalPaddingRight = insets.getSystemWindowInsetRight();
        this.mMetrics.physicalPaddingBottom = 0;
        this.mMetrics.physicalPaddingLeft = insets.getSystemWindowInsetLeft();
        this.mMetrics.physicalViewInsetTop = 0;
        this.mMetrics.physicalViewInsetRight = 0;
        this.mMetrics.physicalViewInsetBottom = insets.getSystemWindowInsetBottom();
        this.mMetrics.physicalViewInsetLeft = 0;
        this.updateViewportMetrics();
        return super.onApplyWindowInsets(insets);
    }

    protected boolean fitSystemWindows(Rect insets) {
        if (VERSION.SDK_INT <= 19) {
            this.mMetrics.physicalPaddingTop = insets.top;
            this.mMetrics.physicalPaddingRight = insets.right;
            this.mMetrics.physicalPaddingBottom = 0;
            this.mMetrics.physicalPaddingLeft = insets.left;
            this.mMetrics.physicalViewInsetTop = 0;
            this.mMetrics.physicalViewInsetRight = 0;
            this.mMetrics.physicalViewInsetBottom = insets.bottom;
            this.mMetrics.physicalViewInsetLeft = 0;
            this.updateViewportMetrics();
            return true;
        } else {
            return super.fitSystemWindows(insets);
        }
    }

    private boolean isAttached() {
        return this.mNativeView != null && this.mNativeView.isAttached();
    }

這裏又涉及到幾個概念,基本都不怎麼經常使用:
WindowInsets,onApplyWindowInsets:
https://blog.csdn.net/me_touc...
fitSystemWindows:
https://blog.csdn.net/ys40897...

static final class ViewportMetrics {
        float devicePixelRatio = 1.0F;
        int physicalWidth = 0;
        int physicalHeight = 0;
        int physicalPaddingTop = 0;
        int physicalPaddingRight = 0;
        int physicalPaddingBottom = 0;
        int physicalPaddingLeft = 0;
        int physicalViewInsetTop = 0;
        int physicalViewInsetRight = 0;
        int physicalViewInsetBottom = 0;
        int physicalViewInsetLeft = 0;

        ViewportMetrics() {
        }
    }

這段代碼的意思顯然是適配窗口大小的變化,並在恰當的時候更新mMetrics,並設置到native中

private static native void nativeSetViewportMetrics(long nativePlatformViewAndroid,
            float devicePixelRatio, int physicalWidth, int physicalHeight, int physicalPaddingTop,
            int physicalPaddingRight, int physicalPaddingBottom, int physicalPaddingLeft,
            int physicalViewInsetTop, int physicalViewInsetRight, int physicalViewInsetBottom,
            int physicalViewInsetLeft);

繼續:

Activity activity = (Activity)this.getContext();
        if (nativeView == null) {
            this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
        } else {
            this.mNativeView = nativeView;
        }

NativeView是什麼?

public class FlutterNativeView implements BinaryMessenger {
...
public FlutterNativeView(Context context) {
        this.mContext = context;
        // 插件管理
        this.mPluginRegistry = new FlutterPluginRegistry(this, context);
        this.attach(this);
        this.assertAttached();
        // 消息管理
        this.mMessageHandlers = new HashMap();
    }
...
    //涉及到和native打交道
private static native long nativeAttach(FlutterNativeView var0);

    private static native void nativeDestroy(long var0);

    private static native void nativeDetach(long var0);

    private static native void nativeRunBundleAndSnapshot(long var0, String var2, String var3, String var4, boolean var5, AssetManager var6);

    private static native void nativeRunBundleAndSource(long var0, String var2, String var3, String var4);

    private static native void nativeSetAssetBundlePathOnUI(long var0, String var2);

    private static native String nativeGetObservatoryUri();

    private static native void nativeDispatchEmptyPlatformMessage(long var0, String var2, int var3);

    private static native void nativeDispatchPlatformMessage(long var0, String var2, ByteBuffer var3, int var4, int var5);

    private static native void nativeInvokePlatformMessageEmptyResponseCallback(long var0, int var2);

    private static native void nativeInvokePlatformMessageResponseCallback(long var0, int var2, ByteBuffer var3, int var4);
}

NativeView顯然是一個插件、消息的管理類,並與native打交道,那麼和FlutterView的關係,顯然一個負責展現,一個負責交互。這裏解決了問題(1)

再往下看

this.mSurfaceCallback = new Callback() {
            public void surfaceCreated(SurfaceHolder holder) {
                FlutterView.this.assertAttached();
                FlutterView.nativeSurfaceCreated(FlutterView.this.mNativeView.get(), holder.getSurface(), color);
            }

            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                FlutterView.this.assertAttached();
                FlutterView.nativeSurfaceChanged(FlutterView.this.mNativeView.get(), width, height);
            }

            public void surfaceDestroyed(SurfaceHolder holder) {
                FlutterView.this.assertAttached();
                FlutterView.nativeSurfaceDestroyed(FlutterView.this.mNativeView.get());
            }
        };
        this.getHolder().addCallback(this.mSurfaceCallback);

這裏監聽了SurfaceView的生命週期,並調用native

this.mAccessibilityManager = (AccessibilityManager)this.getContext().getSystemService("accessibility");
        this.mActivityLifecycleListeners = new ArrayList();
        this.mFirstFrameListeners = new ArrayList();
        this.mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE);
        this.mFlutterNavigationChannel = new MethodChannel(this, "flutter/navigation", JSONMethodCodec.INSTANCE);
        this.mFlutterKeyEventChannel = new BasicMessageChannel(this, "flutter/keyevent", JSONMessageCodec.INSTANCE);
        this.mFlutterLifecycleChannel = new BasicMessageChannel(this, "flutter/lifecycle", StringCodec.INSTANCE);
        this.mFlutterSystemChannel = new BasicMessageChannel(this, "flutter/system", JSONMessageCodec.INSTANCE);
        this.mFlutterSettingsChannel = new BasicMessageChannel(this, "flutter/settings", JSONMessageCodec.INSTANCE);
        PlatformPlugin platformPlugin = new PlatformPlugin(activity);
        MethodChannel flutterPlatformChannel = new MethodChannel(this, "flutter/platform", JSONMethodCodec.INSTANCE);
        flutterPlatformChannel.setMethodCallHandler(platformPlugin);
        this.addActivityLifecycleListener(platformPlugin);
        this.mImm = (InputMethodManager)this.getContext().getSystemService("input_method");
        this.mTextInputPlugin = new TextInputPlugin(this);
        this.setLocale(this.getResources().getConfiguration().locale);
        this.setUserSettings();

這段代碼註冊了一些Flutter的自帶插件,主要用於輸入、生命週期、國際化等系統相關的插件,有時間再一個一個分析,先放放。

問題

  • (13)native中的初始化流程?
  • (14)這裏並無看到一行代碼有和繪製圖形有關,那麼在哪裏調用?是否都是在native中調用,怎麼調用的?

解決問題

  • (1)FlutterNativeView和FlutterView有啥區別和聯繫

本篇總結

所有問題:

  • (1)FlutterNativeView和FlutterView有啥區別和聯繫
  • (2)UserLeaveHintListener做用?
  • (3)ViewFactory#retainFlutterNativeView做用?
  • (4)BinaryMessenger做用
  • (5)TextureRegistry做用
  • (6)FlutterView究竟如何建立的
  • (7)retainFlutterNativeView有什麼做用
  • (8)sResourceExtractor.waitForCompletion();在幹什麼?
  • (9)new FlutterView(this.activity, (AttributeSet)null, nativeView);這裏是否能夠解釋前面的問題(1)
  • (10) nativeInit做用?bundle是什麼,如何加載?
  • (11)sIsPrecompiledAsBlobs && sIsPrecompiledAsSharedLibrary這兩個參數具體表明什麼含義,爲何不能同時存在?和flutter的hotload有關嗎,和flutter是調試版本仍是發佈版本有關嗎?
  • (12)flutter中的so庫具體有哪些,有什麼做用?
  • (13)native中的初始化流程?
  • (14)這裏並無看到一行代碼有和繪製圖形有關,那麼在哪裏調用?是否都是在native中調用,怎麼調用的?

大部分問題在這裏都解釋不了,這裏先用一張圖表示一下啓動流程:

clipboard.png

若有疑問,請加qq羣854192563討論

相關文章
相關標籤/搜索