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中是不一样的:
-
FlutterActivity
public RenderMode getRenderMode() { return getBackgroundMode() == BackgroundMode.opaque ? RenderMode.surface : RenderMode.texture; }
说白了在FlutterActivity中RenderMode就是根据是否透明来决定,如果是透明窗体那么就使用
RenderMode.texture
,如果是不透明的就是用RenderMode.surface
-
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常用模式下有两种渲染模式:
-
RenderMode.surface
这种模式性能最好,但是这种模式下的一个 FlutterView 不能定位在 z-index 中其他 2 个 Android Views 之间,也不能进行动画/转换。除非需要 android.graphics.SurfaceTexture 的特殊功能,否则强烈建议开发人员使用这种渲染模式。
-
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 机制源码深入分析