flutter_boost
flutter_boost copied to clipboard
[Bug]: Android 使用PlatformView加载原生播放器时,退入后台,再次进入,页面发生卡顿问题
请描述遇到的问题,以及您所期望的正确的结果
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的情况是否可行。
用example的image_picker demo
选择视频播放能够重现这个问题么?我试了下是正常的
感谢您的回复,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,返回,进入后台,再回来,必现列表卡死,无法滚动的情况。
我们遇到的问题,类似下边这种。
使用Flutter 3.19的SDK,是否参照 #1960 中,使用了临时方案解决兼容问题?
我也遇到类似问题,临时解决方案也合入了。
我发现有PlatformView时,flutter使用FlutterImageView进行渲染,boost在onPause中将FlutterReneder的isDisplayingFlutterUi属性设为false。推到后台时FlutterJni的onEndFrame触发然后是platformViewsController的onEndFrame方法,该方法内部会执行FlutterView的revertImageView
revertImageView方法中调用了render的addIsDisplayingFlutterUiListener方法。该方法会判断isDisplayingFlutterUi的属性值如果为true会回调listener的onFlutterUiDisplayed方法
listener的回调会执行releaseImageView
但是由于boost在onPause中通过反射更改了改值,造成listener后续不会回调,releaseImageView就不会执行。
flutterImageView就会覆盖在flutterTextureView上方界面就不会相应点击、滑动事件。
不知道分析的对不对,麻烦大家一起看看
@coderloveryan 你这个的现象,就是example里的webview example
,再open flutter page
后,上个页面的NativeView被带到了下个页面去了吧?这个我重现了。
@joechan-cq 是的,打开一个新的页面会被带到下一个页面。另外一种情况是如果嵌入的NativeView是视频播放的view,切换后台再切换回来页面由于覆盖了flutterImageView,不会响应事件给用户感觉就是页面卡死。
官方的PlatformView还有不少问题,例如:
https://github.com/flutter/flutter/issues/113826 https://github.com/flutter/flutter/issues/121687
PlatformView被带到下个页面,这个我有个疑问,https://github.com/flutter/flutter/issues/113826 里因为attachToView
在新容器上重新被调用,所以之前的platformViews
和platformViewParent
都被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,所以platformViewParent
被View.VISIBLE
了,所以显示了出来。 @0xZOne
PlatformView被带到下个页面,这个我有个疑问,flutter/flutter#113826 里因为
attachToView
在新容器上重新被调用,所以之前的platformViews
和platformViewParent
都被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,所以platformViewParent
被View.VISIBLE
了,所以显示了出来。 @0xZOne
这是很久之前提的issue,好久没有看这块代码了:我理解,onDisplayPlatformView这个函数,只要是包含了HC的platformview都会执行才对呀,不管是使用flutterboost的混合应用,还是纯Flutter应用。
我差不多找到原因了。我去测试了iOS,发现iOS上是好的,那说明Flutter层基本是没有问题的,那问题就出在Native层。
首先onDisplayPlatformView
这个函数,在打开具有platformView
或在有platformView
的界面刷新时,是会调用的。但是以newContainer=false形式从有platformView
的页面到无platformView
的页面时(和纯Flutter一样),最后只会触发onBegineFrame
->onEndFrame
,是不会触发onDisplayPlatformView
的。
而以newContainer=true形式打开页面,最后的流程是onBegineFrame
->onDisplayPlatformView
->onEndFrame
。所以PlatformView仍然显示了出来,我和之前描述一样。
所以我猜想,可能是因为跳转新容器时,在新老容器上detachEngine
和attachEngine
之间存在间隔,导致那几次没有onDisplayPlatformView
的流程,没有被Android Java层接收到。所以platformView
被add并visible了。于是我尝试将detachEngine和attachEngine的流程,都修改到FlutterBoostActivity
的onCreate
生命周期中,去除中间onResume
中onContainerAppeared
所产生的间隔,然后再测试,就发现这次newContainer=true
打开新容器时,能够接收到丢失了的不包含onDisplayPlatformView
的onBeginFrame
->onEndFrame
流程了,platformView
也不会显示到新页面上去了。