flutter_boost icon indicating copy to clipboard operation
flutter_boost copied to clipboard

[Bug]: Android 使用PlatformView加载原生播放器时,退入后台,再次进入,页面发生卡顿问题

Open xianwenhua opened this issue 10 months ago • 10 comments

请描述遇到的问题,以及您所期望的正确的结果

Android 使用PlatformView加载原生播放器时,退入后台,再次进入,Flutter页面发生卡顿问题。

请说明如何操作会遇到上述问题

这个bug修改 https://github.com/alibaba/flutter_boost/commit/019e0affc5e80d9f592f0399fe970b5047357215,再进入后台时,将isNeedHookFlutterDisplay通过反射修改false。 进入前台后 FlutterRenderer 以下代码逻辑不执行。 /**

  • Adds a listener that is invoked whenever this {@code FlutterRenderer} starts and stops painting
  • pixels to an Android {@code View} hierarchy. */ public void addIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener) { flutterJNI.addIsDisplayingFlutterUiListener(listener);
**if (isDisplayingFlutterUi) {
  listener.onFlutterUiDisplayed();
}**

} 图中标记的代码不会执行,产生问题

在下面填入关键复现代码

**FlutterBoostActivity**

protected void onPause() {
      // ... 省略部分代码
      setIsFlutterUiDisplayed(false)
}

private void setIsFlutterUiDisplayed(boolean isDisplayed) {
        try {
            FlutterRenderer flutterRenderer = this.getFlutterEngine().getRenderer();
            Field isDisplayingFlutterUiField = FlutterRenderer.class.getDeclaredField("isDisplayingFlutterUi");
            isDisplayingFlutterUiField.setAccessible(true);
            isDisplayingFlutterUiField.setBoolean(flutterRenderer, false);

            assert !flutterRenderer.isDisplayingFlutterUi();
        } catch (Exception var4) {
            Log.e("FlutterBoostActivity", "You *should* keep fields in io.flutter.embedding.engine.renderer.FlutterRenderer.");
            var4.printStackTrace();
        }

    }

### 复现的平台

Android

### Flutter SDK版本

3.19.3

### FlutterBoost版本

5.0.1

### 是否延迟初始化FlutterBoost

No

### 解决方案

想了解如果再进入页面时候修改为isDisplayingFlutterUi  = true的情况是否可行。

xianwenhua avatar Apr 19 '24 03:04 xianwenhua

用example的image_picker demo选择视频播放能够重现这个问题么?我试了下是正常的

joechan-cq avatar Apr 22 '24 06:04 joechan-cq

感谢您的回复,example我测试了,在以下情况下会出现问题: 必现路径为: 1,点击 open flutter page。 2,点击image_picker_demo 3,返回,进入后台 4,出现白屏

另一种问题: 1,点击 open flutter page。 2,点击image_picker_demo。 3,点击键盘弹出,进入后台,再回来,必现列表卡死,无法滚动的情况。

类似上一个问题: 1,点击 open flutter page。 2,点击image_picker_demo,返回,进入后台,再回来,必现列表卡死,无法滚动的情况。

我们遇到的问题,类似下边这种。

xianwenhua avatar Apr 22 '24 07:04 xianwenhua

使用Flutter 3.19的SDK,是否参照 #1960 中,使用了临时方案解决兼容问题?

joechan-cq avatar Apr 22 '24 09:04 joechan-cq

我也遇到类似问题,临时解决方案也合入了。 我发现有PlatformView时,flutter使用FlutterImageView进行渲染,boost在onPause中将FlutterReneder的isDisplayingFlutterUi属性设为false。推到后台时FlutterJni的onEndFrame触发然后是platformViewsController的onEndFrame方法,该方法内部会执行FlutterView的revertImageView PrYzFMYoHi revertImageView方法中调用了render的addIsDisplayingFlutterUiListener方法。该方法会判断isDisplayingFlutterUi的属性值如果为true会回调listener的onFlutterUiDisplayed方法 N94ibp1NeO listener的回调会执行releaseImageView yFDpi9mfrZ 但是由于boost在onPause中通过反射更改了改值,造成listener后续不会回调,releaseImageView就不会执行。 tnXILcDFtZ flutterImageView就会覆盖在flutterTextureView上方界面就不会相应点击、滑动事件。 不知道分析的对不对,麻烦大家一起看看

coderloveryan avatar Apr 22 '24 10:04 coderloveryan

@coderloveryan 你这个的现象,就是example里的webview example,再open flutter page后,上个页面的NativeView被带到了下个页面去了吧?这个我重现了。

joechan-cq avatar Apr 22 '24 11:04 joechan-cq

@joechan-cq 是的,打开一个新的页面会被带到下一个页面。另外一种情况是如果嵌入的NativeView是视频播放的view,切换后台再切换回来页面由于覆盖了flutterImageView,不会响应事件给用户感觉就是页面卡死。

coderloveryan avatar Apr 22 '24 11:04 coderloveryan

官方的PlatformView还有不少问题,例如:

https://github.com/flutter/flutter/issues/113826 https://github.com/flutter/flutter/issues/121687

0xZOne avatar Apr 24 '24 02:04 0xZOne

PlatformView被带到下个页面,这个我有个疑问,https://github.com/flutter/flutter/issues/113826 里因为attachToView在新容器上重新被调用,所以之前的platformViewsplatformViewParent都被add到了FlutterView上。但对于纯Flutter而言,这些View原本就已经在FlutterView上了,因此FlutterBoost将其重新add到新的FlutterView上的逻辑在我看来没有问题。我跟下来,发现的区别是纯Flutter,打开新页面时,最后触发PlatformViewController中的onBeginFrame->onEndFrame,而FlutterBoost是触发onBeginFrame->onDisplayPlatformView->onEndFrame,这个onDisplayPlatformView就导致currentFrameUsedPlatformViewIds不为空,所以纯Flutter会在onEndFrame中触发finishframe(false),而FlutterBoost不会,且因为isFrameRenderedUsingImageReaders为true,所以platformViewParentView.VISIBLE了,所以显示了出来。 @0xZOne

joechan-cq avatar Apr 24 '24 11:04 joechan-cq

PlatformView被带到下个页面,这个我有个疑问,flutter/flutter#113826 里因为attachToView在新容器上重新被调用,所以之前的platformViewsplatformViewParent都被add到了FlutterView上。但对于纯Flutter而言,这些View原本就已经在FlutterView上了,因此FlutterBoost将其重新add到新的FlutterView上的逻辑在我看来没有问题。我跟下来,发现的区别是纯Flutter,打开新页面时,最后触发PlatformViewController中的onBeginFrame->onEndFrame,而FlutterBoost是触发onBeginFrame->onDisplayPlatformView->onEndFrame,这个onDisplayPlatformView就导致currentFrameUsedPlatformViewIds不为空,所以纯Flutter会在onEndFrame中触发finishframe(false),而FlutterBoost不会,且因为isFrameRenderedUsingImageReaders为true,所以platformViewParentView.VISIBLE了,所以显示了出来。 @0xZOne

这是很久之前提的issue,好久没有看这块代码了:我理解,onDisplayPlatformView这个函数,只要是包含了HC的platformview都会执行才对呀,不管是使用flutterboost的混合应用,还是纯Flutter应用。

0xZOne avatar Apr 28 '24 04:04 0xZOne

我差不多找到原因了。我去测试了iOS,发现iOS上是好的,那说明Flutter层基本是没有问题的,那问题就出在Native层。

首先onDisplayPlatformView 这个函数,在打开具有platformView或在有platformView的界面刷新时,是会调用的。但是以newContainer=false形式从有platformView的页面到无platformView的页面时(和纯Flutter一样),最后只会触发onBegineFrame->onEndFrame,是不会触发onDisplayPlatformView的。

image

而以newContainer=true形式打开页面,最后的流程是onBegineFrame->onDisplayPlatformView->onEndFrame。所以PlatformView仍然显示了出来,我和之前描述一样。

image

所以我猜想,可能是因为跳转新容器时,在新老容器上detachEngineattachEngine之间存在间隔,导致那几次没有onDisplayPlatformView的流程,没有被Android Java层接收到。所以platformView被add并visible了。于是我尝试将detachEngine和attachEngine的流程,都修改到FlutterBoostActivityonCreate生命周期中,去除中间onResumeonContainerAppeared所产生的间隔,然后再测试,就发现这次newContainer=true打开新容器时,能够接收到丢失了的不包含onDisplayPlatformViewonBeginFrame->onEndFrame流程了,platformView也不会显示到新页面上去了。

image

joechan-cq avatar Apr 28 '24 06:04 joechan-cq