void FlutterPlatformViewsController::OnCreate(FlutterMethodCall* call, FlutterResult& result) {NSDictionary<NSString*, id>* args = [call arguments];long viewId = [args[@"id"] longValue];NSObject<FlutterPlatformView>* embedded_view = [factory createWithFrame:CGRectZeroviewIdentifier:viewIdarguments:params]; // 初始化UIView* platform_view = [embedded_view view];FlutterTouchInterceptingView* touch_interceptor = [[[FlutterTouchInterceptingView alloc]initWithEmbeddedView:platform_viewplatformViewsController:GetWeakPtr()gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies[viewType]]autorelease];ChildClippingView* clipping_view =[[[ChildClippingView alloc] initWithFrame:CGRectZero] autorelease];[clipping_view addSubview:touch_interceptor];root_views_[viewId] = fml::scoped_nsobject<UIView>([clipping_view retAIn]); // 缓存}生成当前帧的 Layer Tree 之后,会进入到 Rasterizer 流程 。首先会调用 BeginFrame 渲染一帧,触发 PlatformViewLayer::Preroll,PlatformViewLayer 标记出当前帧有 PlatformView ,然后调用 FlutterPlatformViewsController::PrerollCompositeEmbeddedView 更新 view_params_,包含 Platform View 坐标、size 等信息,最后在 SubmitFrame 方法中取出 native view 添加到 flutter view 中,完成渲染 。
void PlatformViewLayer::Preroll(PrerollContext* context,const SkMatrix& matrix) {set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(),size_.height()));context->has_platform_view = true;set_subtree_has_platform_view(true); // 标记当前帧存在Platform Viewstd::unique_ptr<EmbeddedViewParams> params =std::make_unique<EmbeddedViewParams>(matrix, size_,context->mutators_stack);context->view_embedder->PrerollCompositeEmbeddedView(view_id_,std::move(params));}3.3 PlatformView 是如何实现帧同步?
在原生开发中,我们知道UI操作不能在其他线程执行,会出现帧不同步的问题 。flutter Engine 中有 platform、ui、raster、io四个线程,native view 是在 Platform Thread(主线程)渲染,而 flutter 渲染正常情况在 Raster Thread 执行的,flutter 又是如何保证帧同步的呢?
flutter 解决帧同步是通过线程合并的方案 。上图 Raster 流程 PostPrerollAction 方法中,会判断如果有 PlatformView 存在,在接下来的绘制过程中 Raster Thread 与 Platform Thread 会合并,将 Raster 队列任务放到 Platform 队列中 。这样所有的渲染任务都在 Platform Thread 中执行,保证了画面的同步 。
PostPrerollResult FlutterPlatformViewsController::PostPrerollAction(fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {if (!HasPlatformViewThisOrNextFrame()) { // 没有Platform View不用处理return PostPrerollResult::kSuccess;}if (!raster_thread_merger->IsMerged()) { // 线程还没有并不用处理CancelFrame(); // 取消绘制当前帧return PostPrerollResult::kSkipAndRetryFrame; // 合并后完成当前帧}BeginCATransaction();raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);return PostPrerollResult::kSuccess;}// 合并队列bool MessageLoopTaskQueues::Merge(TaskQueueId owner, TaskQueueId subsumed) {if (owner == subsumed) {return true;}std::lock_guard guard(queue_mutex_);auto& owner_entry = queue_entries_.at(owner);auto& subsumed_entry = queue_entries_.at(subsumed);auto& subsumed_set = owner_entry->owner_of;if (subsumed_set.find(subsumed) != subsumed_set.end()) {return true;}owner_entry->owner_of.insert(subsumed);subsumed_entry->subsumed_by = owner;if (HasPendingTasksUnlocked(owner)) {WakeUpUnlocked(owner, GetNextWakeTimeUnlocked(owner));}return true;}四、问题及解决方案4.1 IOS 页面切换 Map 组件白屏问题
在使用 flutter_boost 混合开发时,当 A 页面中使用 platformview,开启新容器跳转到 flutter B 页面,platformView 会出现短暂的白屏,从 A 页面跳转 native 页面不会出现 。根据表象首先猜测是单引擎导致的 。flutter A页面跳转到其他页面时都会触发 SceneBuilder::pushTransform 重新渲染一次 A 页面 。
void SceneBuilder::pushTransform(Dart_Handle layer_handle,tonic::Float64List& matrix4,fml::RefPtr<EngineLayer> oldLayer) {SkMatrix sk_matrix = ToSkMatrix(matrix4);auto layer = std::make_shared<flutter::TransformLayer>(sk_matrix);PushLayer(layer);// matrix4 has to be released before we can return another Dart objectmatrix4.Release();EngineLayer::MakeRetained(layer_handle, layer);if (oldLayer && oldLayer->Layer()) {layer->AssignOldLayer(oldLayer->Layer().get());}}flutter A页面在创建新容器 push 到 flutter B 页面时,首先会触发 viewDidLayoutSubviews,方法内部会修改 engine 对应的 viewController flutterView,SceneBuilder::pushTransform 是在 viewDidLayoutSubviews 之后还会触发,而 platformView 是在 native 渲染,重新渲染 A 页面时就找不到对应的 platformView,导致白屏的问题 。push 到非 flutter 页面时不会触发 surfaceUpdated,所以不会出现该问题 。
推荐阅读
- 今天来了解一下什么是导热硅脂吧
- 算力正在狂飙,未来需更多联想
- 夏季钓鲫鱼,钓位不能胡乱选,大鲫鱼就在2种位置
- 何洁参加《天赐4》,在台上开怼评委,不接受对方意见遭吐槽
- 袁泉树立新标杆,无视网友大胆开麦,背后究竟是谁在撑腰?
- 闷竿高手的方法,持续诱鱼,不断上鱼,学会也是高手
- 大清铜币户部现在什么价位 最高成交价500多万
- DNF7.06夏日版本终于在体验服露脸了
- 事实证明,“飞扬跋扈”的周冬雨,已经在另一个圈子里如鱼得水
- 在职场,叫苦不如吃苦,生气不如争气
