Flutter实践深入分析之——FlutterView相关源码分析

Posted Beason_H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter实践深入分析之——FlutterView相关源码分析相关的知识,希望对你有一定的参考价值。

前言

​ 通过前面文章的分析我们了解到FlutterActivity的显示最终是通过FlutterView进行渲染。本文我们深入FlutterView的源码来具体分析下Flutter UI是如何一步步显示到Activity,又是如何跟Flutter Engine关联,下面来看一下FlutterView的大致相关类:


Flutter渲染模式

要了解FlutterView我们首先来了解一下Flutter的RenderMode,在Flutter里面渲染模式分为三种:RenderMode.surface、RenderMode.texture、RenderMode.image,前面两种模式是在接口FlutterActivityAndFragmentDelegate.Host接口getRenderMode()方法中返回,其内部的判断条件在FlutterActivity和FlutterFragment中是不一样的:

  1. FlutterActivity

      public RenderMode getRenderMode() {
        return getBackgroundMode() == BackgroundMode.opaque ? RenderMode.surface : RenderMode.texture;
      }
    

    说白了在FlutterActivity中RenderMode就是根据是否透明来决定,如果是透明窗体那么就使用RenderMode.texture,如果是不透明的就是用RenderMode.surface

  2. FlutterFragment

      public RenderMode getRenderMode() {
        String renderModeName =
            getArguments().getString(ARG_FLUTTERVIEW_RENDER_MODE, RenderMode.surface.name());
        return RenderMode.valueOf(renderModeName);
      }
    

    而在FlutterFragment中RenderMode是通过ARG_FLUTTERVIEW_RENDER_MODE参数来决定。

思考:为什么透明模式下使用RenderMode.texture,而不透明模式下使用RenderMode.surface

显而易见三种渲染模式对应的在FlutterView创建时以来不同的类,分别是:FlutterSurfaceView,FlutterTextureView,FlutterImageView。下面我们一起来看看这三个类。

FlutterSurfaceView分析

从文中开头大致的类图关系我们知道FlutterSurfaceView、FlutterTextureView和FlutterImageView都是FlutterView的一个成员变量,通过构造函数根据不同的渲染模式传递对应的参数对FlutterView进行初始化。

//继承自SurfaceView,实现RenderSurface接口
public class FlutterSurfaceView extends SurfaceView implements RenderSurface {
    private final SurfaceHolder.Callback surfaceCallback =
      new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(@NonNull SurfaceHolder holder) {
            //......
            connectSurfaceToRenderer();
        }

        @Override
        public void surfaceChanged(
            @NonNull SurfaceHolder holder, int format, int width, int height) {
          	//....
          	changeSurfaceSize(width, height);
        }

        @Override
        public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
						//...
          	disconnectSurfaceFromRenderer();
        }
      };
 			
  	private void connectSurfaceToRenderer() {
      if (flutterRenderer == null || getHolder() == null) {
        throw new IllegalStateException(
            "connectSurfaceToRenderer() should only be called when flutterRenderer and getHolder() are non-null.");
      }

      flutterRenderer.startRenderingToSurface(getHolder().getSurface());
  	}
  /**
  * 当 FlutterSurfaceView 想要开始将 Flutter UI 渲染到此 FlutterSurfaceView 时,由此 FlutterSurfaceView 的所有者调用。
	*	如果 android android.view.Surface 可用,则此方法会将 android.view.Surface 提供给给定的 FlutterRenderer 以开始将 Flutter 的 UI 渲染到此 	 *FlutterSurfaceView。
	*	如果还没有 Android android.view.Surface 可用,则此 FlutterSurfaceView 将等到 android.view.Surface 可用,然后将该 				     
	* android.view.Surface 提供给给定的 FlutterRenderer 以开始将 Flutter 的 UI 渲染到此 FlutterSurfaceView。
  */
  public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
    connectSurfaceToRenderer();
  }

 	/***
 	当 FlutterSurfaceView 不再想将 Flutter UI 渲染到此 FlutterSurfaceView 时,由此 FlutterSurfaceView 的所有者调用。此方法将停止从 Flutter 到此 FlutterSurfaceView 的任何正在进行的渲染。
	***/
  public void detachFromRenderer() {
    disconnectSurfaceFromRenderer();
  }

  // FlutterRenderer and getSurfaceTexture() must both be non-null.
  private void connectSurfaceToRenderer() {
    flutterRenderer.startRenderingToSurface(getHolder().getSurface());
  }

  // FlutterRenderer must be non-null.
  private void changeSurfaceSize(int width, int height) {
    flutterRenderer.surfaceChanged(width, height);
  }

  // FlutterRenderer must be non-null.
  private void disconnectSurfaceFromRenderer() {
    flutterRenderer.stopRenderingToSurface();
  }
}

​ 上面的代码逻辑相当简介易懂,可以看到,FlutterSurfaceView实际上是一个SurfaceView,用法也是跟SurfaceView一样,只是渲染数据是最终是通过flutterJNI作为桥梁实现Flutter Engine与Android View层进行数据传递实现界面绘制的。

FlutterTextureView分析

与上面的FlutterSurfaceView一样,逻辑实现简洁易懂,先看看主要逻辑:

//继承自TextureView,实现RenderSurface接口
public class FlutterTextureView extends TextureView implements RenderSurface {
  private final SurfaceTextureListener surfaceTextureListener =
      new SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(
            SurfaceTexture surfaceTexture, int width, int height) {
            connectSurfaceToRenderer();
        }

        @Override
        public void onSurfaceTextureSizeChanged(
            @NonNull SurfaceTexture surface, int width, int height) {
            changeSurfaceSize(width, height);
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
          // Invoked every time a new frame is available. We don't care.
        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
          disconnectSurfaceFromRenderer();
          return true;
        }
      };


  public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
      connectSurfaceToRenderer();
  }

  public void detachFromRenderer() {
      disconnectSurfaceFromRenderer();
  }

  private void connectSurfaceToRenderer() {
    renderSurface = new Surface(getSurfaceTexture());
    flutterRenderer.startRenderingToSurface(renderSurface);
  }

  private void changeSurfaceSize(int width, int height) {
    flutterRenderer.surfaceChanged(width, height);
  }

  private void disconnectSurfaceFromRenderer() {
    flutterRenderer.stopRenderingToSurface();
    if (renderSurface != null) {
      renderSurface.release();
      renderSurface = null;
    }
  }
}

从上面的代码可以看到FlutterTextureView和FlutterSurfaceView的逻辑基本一致,唯一不同的就是提供的Surface来源不一样,逻辑很简单这里不做多余介绍。

FlutterImageView分析

FlutterImageView并不是一个真正意义上的ImageView。它的工作流程和FlutterTextureView,FlutterSurfaceView工作流程极度相似,但是它的使用场景却完全不一样,想要了解FlutterImageView的工作场景,必须要先了解Flutter的Hybrid Composition工作模式。由于Hybrid Composition 模式涉及到的内容关联比较多,下次单独讲解。这里简单理解来讲Hybrid Composition模式就是解决原生控件和Flutter混合显示问题。

我们来看下FlutterImageView源码:

@TargetApi(19)
public class FlutterImageView extends View implements RenderSurface {
  
  // 原生控件的绘制操作
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    if (!imageQueue.isEmpty()) {
      if (currentImage != null) {
        currentImage.close();
      }
      currentImage = imageQueue.poll();
      updateCurrentBitmap();
    }
    if (currentBitmap != null) {
      canvas.drawBitmap(currentBitmap, 0, 0, null);
    }
  }
}

我们可以看到FlutterImageView实际上就是一个原生的View,但是它又实现了RenderSurface接口,不难判断FlutterImageView既可以显示渲染我们的FlutterUI,又可以显示渲染我们的原生View。它的使用场景已经原理分享后面再花费专题文章讲解。

FlutterRender分析

通过上面的分析,我们知道FlutterRenderer 的主要职责最终是通过 FlutterJNI 进行渲染关联处理,与原生平台提供的 FlutterSurfaceView、FlutterTextureView 、FlutterImageView进行纯 UI 渲染,将 Flutter 像素绘制到 Android 视图层次结构。

public class FlutterRenderer implements TextureRegistry {
  //......
  @NonNull private final FlutterJNI flutterJNI;
  @Nullable private Surface surface;
  //......
}

通过上面源码的两个属性成员就能看出来他的职责。

FlutterView分析

通俗来说FlutterView 的作用是在 Android 设备上显示一个 Flutter UI,绘制内容来自于 FlutterEngine 的flutterJNI提供。FlutterView常用模式下有两种渲染模式:

  1. RenderMode.surface

    这种模式性能最好,但是这种模式下的一个 FlutterView 不能定位在 z-index 中其他 2 个 Android Views 之间,也不能进行动画/转换。除非需要 android.graphics.SurfaceTexture 的特殊功能,否则强烈建议开发人员使用这种渲染模式。

  2. RenderMode.texture

    它将 Flutter UI 绘制到 android.graphics.SurfaceTexture。这种模式的性能不如 io.flutter.embedding.android.RenderMode.surface,但这种模式下的 FlutterView 可以进行动画和变换,也可以定位在 2+ 其他 Android 视图之间的 z-index 中。除非需要 android.graphics.SurfaceTexture 的特殊功能,否则开发人员应该强烈推荐

FlutterView 的默认构造器就是 surface 模式

下面我们再来分析下FlutterView,首先我们来看看它的变量和构造函数声明

public class FlutterView extends FrameLayout implements MouseCursorPlugin.MouseCursorViewDelegate {
  private static final String TAG = "FlutterView";

  // 用来真正渲染绘制视图的相关类
  @Nullable private FlutterSurfaceView flutterSurfaceView;
  @Nullable private FlutterTextureView flutterTextureView;
  @Nullable private FlutterImageView flutterImageView;
  @Nullable private RenderSurface renderSurface;
  @Nullable private RenderSurface previousRenderSurface;

  //与 FlutterEngine连接
  @Nullable private FlutterEngine flutterEngine;

  // 处理各种类型的 Android View 输入和事件的组件
  @Nullable private MouseCursorPlugin mouseCursorPlugin;
  @Nullable private TextInputPlugin textInputPlugin;
  @Nullable private LocalizationPlugin localizationPlugin;
  @Nullable private AndroidKeyProcessor androidKeyProcessor;
  @Nullable private AndroidTouchProcessor androidTouchProcessor;
  @Nullable private AccessibilityBridge accessibilityBridge;

  //构造函数,默认模式为surface
  private FlutterView(
      @NonNull Context context,
      @Nullable AttributeSet attrs,
      @NonNull FlutterSurfaceView flutterSurfaceView) {
    super(context, attrs);

    this.flutterSurfaceView = flutterSurfaceView;
    this.renderSurface = flutterSurfaceView;

    init();
  }

  //构造函数,模式为texture
  private FlutterView(
      @NonNull Context context,
      @Nullable AttributeSet attrs,
      @NonNull FlutterTextureView flutterTextureView) {
    super(context, attrs);

    this.flutterTextureView = flutterTextureView;
    this.renderSurface = flutterTextureView;

    init();
  }

  //构造函数 模式为image
  @TargetApi(19)
  private FlutterView(
      @NonNull Context context,
      @Nullable AttributeSet attrs,
      @NonNull FlutterImageView flutterImageView) {
    super(context, attrs);

    this.flutterImageView = flutterImageView;
    this.renderSurface = flutterImageView;

    init();
  }

  //根据不同的模式指定RenderSurface
  private void init() {
    if (flutterSurfaceView != null) {
      addView(flutterSurfaceView);
    } else if (flutterTextureView != null) {
      addView(flutterTextureView);
    } else {
      addView(flutterImageView);
    }
  }

通过上面的代码我们知道FlutterView其实是一个原生的继承自FrameLayout的ViewGroup。在init中根据不同的模式添加不同的View从而指定surface,也就是 FlutterSurfaceView、FlutterTextureView、FlutterImageView 之一。而最终FlutterEngine渲染数据到不同的surface。


总结(类图,架构图)

类关系图

架构图

图是按照理解绘制的,比较粗略有问题欢迎留言

以上是关于Flutter实践深入分析之——FlutterView相关源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Flutter实践深入分析之——FlutterActivity/Fragment原理流程分析

Flutter实践深入分析之——FlutterActivity/Fragment原理流程分析

Flutter实践深入——平台整合Hybrid composition分析

Flutter 命令本质之 Flutter tools 机制源码深入分析

Flutter 命令本质之 Flutter tools 机制源码深入分析

Flutter 命令本质之 Flutter tools 机制源码深入分析