- (void)viewDidLayoutSubviews {...if (firstViewBoundsUpdate && ApplicationIsActive && _engine) {[self surfaceUpdated:YES];}...}- (void)surfaceUpdated:(BOOL)appeared {if (appeared) {[self installFirstFrameCallback];[_engine.get() platformViewsController]->SetFlutterView(_flutterView.get());[_engine.get()platformViewsController]->SetFlutterViewController(self);[_engine.get() iosPlatformView]->NotifyCreated();}}一开始的方案是在 viewWillAppear 中调用 sufaceUpdated,但是在 release 环境中会出现卡死的现象 。另一方案是 [super bridge_viewWillAppear:animated]; 改为 [super viewWillAppear:animated]; [super viewWillAppear:animated]; 会调用父类的方法,父类方法又会调用 sufaceUpdated,就可以解决白屏的问题 。
4.2 Android 地图卡死不能操作问题
1)问题描述
A 页面内嵌地图,跳转到 B 页面 。然后返回 A 页面,地图就不能滑动 。
结合上文提到的 Flutter 地图插件其实是通过 MathodChannel 将操作传递到 Native 的地图视图处理的 。我们调试 Native 的代码发现 PlatformViewsController 类里面的 onTouch()方法中,context 报了一个Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference 。
public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {final float density = context.getResources().getDisplayMetrics().density;}2)分析问题
由于 context 对象被回收,造成的报错 。现在我们只有分析出来为什么 context 对象会被回收掉了就能找出问题了,读源码发现只有在 detach() 方法中才会回收 context 对象 。
public void detach() {context = null;}结合日志输出,确实发现回到 A 页面是执行了 attach() 方法,但是马上又执行了 detach() 方法 。现在就是要找出,为什么 A 页面的 PlatformViewsController 会被执行 datach() 。
从B页面 返回A页面2022-08-22 15:13:08.126 21878-21878/ctrip.flutter.demo D/PlatformViewsController: B===>detach()2022-08-22 15:13:08.135 21878-21878/ctrip.flutter.demo D/PlatformViewsController: A====>attach()2022-08-22 15:13:08.249 21878-21878/ctrip.flutter.demo D/PlatformViewsController: A=====>detach()查看调用链:
逐个类读源码我们发现在 FlutterActivityAndFragmentDelegate的OnDetach() 方法中如果引擎的生命周期和 Activity 的生命周期是绑定的 。页面结束时,引擎就会被销毁掉 。
void onDetach() {if (host.shouldAttachEng.NEToActivity()) {if (host.getActivity().isChangingConfigurations()) {flutterEngine.getActivityControlSurface().detachFromactivityForConfigChanges();} else {flutterEngine.getActivityControlSurface().detachFromActivity();}}3)解决问题
设置 shouldAttachEngineToActivity 返回 flase 使得 Flutter 引擎将在应用程序的整个生命周期内持久化存在,并独立于 Activity,当 Activity 被销毁时,Flutter 引擎不被销毁。问题就解决了 。产生问题的原因是我们新开 B 页面是通过新开容器的方式创建的 。B 页面 FlutterFragment 中 onDetach() 方法在 A 页面 onAttach() 之后被执行的 。纯 Flutter 工程或者是采用 Push 的方式打开新页面,不新开容器都能规避掉这个问题 。
public boolean shouldAttachEngineToActivity() {return false;}4.3 Android 地图内存溢出问题
1)问题描述
多次打开 Android Flutter 地图页面会越来越卡,到后面整个地图都黑一下,显然是有内存溢出了 。通过 Android Studio IDE 自带的内存工具 Android Profiler 可以很明显的看出来,每打开一次页面,内存占有都会上升,结束页面内存没有得到释放 。
2)分析问题
Flutter Boost 和地图插件如此大量的第三方代码,我们如何去定位问题呢?是插件引起的,还是框架引起的呢?借助 LeakCanary 就能很好的找到内存泄露的地方了 。
接入也非常的简单,在 Android build.gradle引入leakcanary 。
debugImplementation'com.squareup.leakcanary:leakcanary-android:2.6'然后运行应用,反复操作问题复现流程,直到 LeakCanary 提示 。查看 leaks 内存溢出的堆栈信息 。是由于 SingleViewPresentation 一直持有了容器 TripFlutterActivity 的 context 对象 。怀疑是 MapView 的生命周期有问题 。是不是没有执行 dispose 。调试下来的情况 PlatformViewsHandler handler 对象空了,后面的流程都不会执行 。
3)解决问题
查看源码只有 PaltformViewsController detach() 方法会把 handler 设置为 null 。
public void detach() {if (platformViewsChannel != null) {platformViewsChannel.setPlatformViewsHandler(null);}}调试下来 FlutterActivity 容器结束,调用了 onDestroy() 方法的时候 PaltformViewsController detach() 就已经被执行了 。容器的 onDestroy() 在 MapView 的 dispos e之前,造成了 handler 对象空了 。
推荐阅读
- 今天来了解一下什么是导热硅脂吧
- 算力正在狂飙,未来需更多联想
- 夏季钓鲫鱼,钓位不能胡乱选,大鲫鱼就在2种位置
- 何洁参加《天赐4》,在台上开怼评委,不接受对方意见遭吐槽
- 袁泉树立新标杆,无视网友大胆开麦,背后究竟是谁在撑腰?
- 闷竿高手的方法,持续诱鱼,不断上鱼,学会也是高手
- 大清铜币户部现在什么价位 最高成交价500多万
- DNF7.06夏日版本终于在体验服露脸了
- 事实证明,“飞扬跋扈”的周冬雨,已经在另一个圈子里如鱼得水
- 在职场,叫苦不如吃苦,生气不如争气
