Flutter 1(1)

反复提醒,是 1.20 不是 1.2 ~~~

一、旧版本的 VirtualDisplay

1.20 之前在 Flutter 中通过将 AndroidView 需要渲染的内容绘制到 VirtualDisplays 中 ,然后在 VirtualDisplay 对应的内存中,绘制的画面就可以通过其 Surface 获取得到

VirtualDisplay 类似于一个虚拟显示区域,需要结合 DisplayManager 一起调用,一般在副屏显示或者录屏场景下会用到。VirtualDisplay 会将虚拟显示区域的内容渲染在一个 Surface 上。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如上图所示,简单来说就是原生控件的内容被绘制到内存里,然后 Flutter Engine 通过相对应的 textureId 就可以获取到控件的渲染数据并显示出来

这种实现方式最大的问题就在与触摸事件、文字输入和键盘焦点等方面存在很多诸多需要处理的问题;在 iOS 并不使用类似 VirtualDisplay 的方法,而是通过将 Flutter UI 分为两个透明纹理来完成组合:一个在 iOS 平台视图之下,一个在其上面

所以这样的好处就是:需要在“iOS平台”视图下方呈现的Flutter UI,最终会被绘制到其下方的纹理上;而需要在“平台”上方呈现的Flutter UI,最终会被绘制在其上方的纹理。它们只需要在最后组合起来就可以了

通常这种方法更好,因为这意味着 Native View 可以直接参与到 Flutter 的 UI 层次结构中。

二、 接入 Hybrid Composition

官方和社区不懈的努力下, 1.20 版本开始在 Android 上新增了 Hybrid CompositionPlatformView 实现,该实现将解决以前存在于 Android 上的大部分和 PlatformView 相关的问题,比如华为手机上键盘弹出后 Web 界面离奇消失等玄学异常

使用 Hybrid Composition 需要使用到 PlatformViewLinkAndroidViewSurfacePlatformViewsService 这三个对象,首先我们要创建一个 dart 控件:

  • 通过 PlatformViewLinkviewType 注册了一个和原生层对应的注册名称,这和之前的 PlatformView 注册一样;
  • 然后在 surfaceFactory 返回一个 AndroidViewSurface 用于处理绘制和接受触摸事件;
  • 最后在 onCreatePlatformView 方法使用 PlatformViewsService 初始化 AndroidViewSurface 和初始化所需要的参数,同时通过 Engine 去触发原生层的显示。

Widget build(BuildContext context) {
// This is used in the platform side to register the view.
final String viewType = ‘hybrid-view-type’;
// Pass parameters to the platform side.
final Map<String, dynamic> creationParams = <String, dynamic>{};

return PlatformViewLink(
viewType: viewType,
surfaceFactory:
(BuildContext context, PlatformViewController controller) {
return AndroidViewSurface(
controller: controller,
gestureRecognizers: const <Factory>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
return PlatformViewsService.initSurfaceAndroidView(
id: params.id,
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: StandardMessageCodec(),
)
…addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
…create();
},
);
}

接下来来到 Android 原生层,在原生通过继承 PlatformView 然后通过 getView 方法返回需要渲染的控件。

package dev.flutter.example;

import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.platform.PlatformView;

class NativeView implements PlatformView {
@NonNull private final TextView textView;

NativeView(@NonNull Context context, int id, @Nullable Map<String, Object> creationParams) {
textView = new TextView(context);
textView.setTextSize(72);
textView.setBackgroundColor(Color.rgb(255, 255, 255));
textView.setText("Rendered on a native Android view (id: " + id + “)”);
}

@NonNull
@Override
public View getView() {
return textView;
}

@Override
public void dispose() {}
}

之后再继承 PlatformViewFactory 通过 create 方法来加载和初始化 PlatformView

package dev.flutter.example;

import android.content.Context;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import java.util.Map;

class NativeViewFactory extends PlatformViewFactory {
@NonNull private final BinaryMessenger messenger;
@NonNull private final View containerView;

NativeViewFactory(@NonNull BinaryMessenger messenger, @NonNull View containerView) {
super(StandardMessageCodec.INSTANCE);
this.messenger = messenger;
this.containerView = containerView;
}

@NonNull
@Override
public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
final Map<String, Object> creationParams = (Map<String, Object>) args;
return new NativeView(context, id, creationParams);
}
}

最后在 MainActivity 通过 flutterEnginegetPlatformViewsController 去注册 NativeViewFactory

package dev.flutter.example;

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;

public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
flutterEngine
.getPlatformViewsController()
.getRegistry()
.registerViewFactory(“hybrid-view-type”, new NativeViewFactory(null, null));
}
}

当然,如果需要在 Android 上启用 Hybrid Composition ,还需要在 AndroidManifest.xml 添加如下所示代码来启用配置:




另外,官方表示 Hybrid composition 在 Android 10 以上的性能表现不错,在 10 以下的版本中,Flutter 界面在屏幕上呈现的速度会变慢,这个开销是因为 Flutter 帧需要与 Android 视图系统同步造成的。

为了缓解此问题,应该避免在 Dart 执行动画时显示原生控件,例如可以使用placeholder 来原生控件的屏幕截图,并在这些动画发生时直接使用这个 placeholder

三、 Hybrid Composition 的特点和实现原理

要介绍 Hybrid Composition 的实现,就不得不介绍本次新增的一个对象:FlutterImageView

FlutterImageView 并不是一般意义上的 ImageView

事实上 Hybrid Composition 上混合原生控件所需的图层合成就是通过 FlutterImageView 来实现。FlutterImageView 本身是一个普通的原生 View, 它通过实现了 RenderSurface 接口从而实现如 FlutterSurfaceView 的部分能力。

FlutterImageView 内部主要有 ImageReaderImageBitmap 三种类,其中:

  • ImageReader 可以简单理解为就是能够存储 Image 数据的对象,并且可以提供 Surface 用于绘制接受原生层的 Image 数据。
  • Image 就是包含了 ByteBuffers 的像素数据,它和 ImageReader 一般用在原生的如 Camera 相关的领域。
  • Bitmap 是将 Image 转化为可以绘制的位图,然后在 FlutterImageView 内通过 Canvas 绘制出来。

可以看到 FlutterImageView 可以提供 Surface ,可以读取到 SurfaceImage 数据,然后通过Bitmap 绘制出来。

而在 FlutterImageView 中提供有 backgroundoverlay 两种 SurfaceKind ,其中:

  • background 适用于默认下 FlutterView 的渲染模式,也就是 Flutter 主应用的渲染默认,所以 FlutterView 其实现在有 surfacetextureimage 三种 RenderMode

  • overlay 就是用于上面所说的 Hybrid Composition 下用于和 PlatformView 合成的模式。

总结

最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值