深入解析与彻底解决 Android 集成 Flutter Boost 时页面闪烁问题

在混合开发中,将 Flutter 模块集成到 Android 应用中是一种常见的需求。然而,许多开发者在集成过程中遇到了页面闪烁的问题,这严重影响了用户体验。本文将深入分析这一问题,并提供多种解决方案,帮助开发者彻底解决这一难题。

一、页面闪烁问题分析

  1. 集成方式:

    • Flutter 模块集成在 Android 的 Fragment 中。
    • 从原生页面返回 Flutter 页面时,带有动画的组件出现闪烁。
  2. 问题表现:

    • 从原生页面返回 Flutter 页面时,带有动画的组件(如轮播图)会出现闪烁。
  3. 根本原因:

    • 渲染冲突:Flutter 的渲染过程与原生页面的动画冲突。
    • 生命周期管理:Flutter 页面的生命周期与原生页面的生命周期不一致,导致渲染状态不匹配。

二、解决方案

临时方案一:使用 ValueKey 解决闪烁问题

适用场景:适用于所有页面,但可能会导致性能损失。

解决方案: 通过为带有动画的组件设置 ValueKey,每次重置组件时生成一个新的 ValueKey,从而避免组件被缓存导致的闪烁问题。

示例代码:

dart 复制代码
final Uuid _uuid = const Uuid();
int _currentIndex = 0;

CarouselSlider(
  key: ValueKey(_uuid.v4()),
  carouselController: _controller,
  items: [
    // 轮播图项
  ],
  options: CarouselOptions(
    autoPlay: true,
    enlargeCenterPage: true,
    viewportFraction: 1.0,
    onPageChanged: (index, reason) {
      _currentIndex = index;
    },
  ),
);

优点:

  • 简单易用,可以解决所有闪烁问题。

缺点:

  • 每次重置组件时都会重新渲染,可能导致性能损失。

临时方案二:在 onResumeonPause 中控制渲染

适用场景:适用于大部分页面,但少部分页面可能仍会出现问题。

解决方案: 在 FlutterActivityFlutterFragment 中手动控制 Flutter 页面的生命周期,确保 Flutter 页面在正确的时间进入前台和后台。

示例代码:

kotlin 复制代码
class AppFlutterActivity : FlutterBoostActivity() {

    override fun onResume() {
        super.onResume()
        try {
            FlutterBoost.instance().plugin.onForeground()
        } catch (e: Exception) {
            // 忽略异常
        }
    }

    override fun onPause() {
        super.onPause()
        try {
            FlutterBoost.instance().plugin.onBackground()
        } catch (e: Exception) {
            // 忽略异常
        }
    }
}

FlutterFragment 中处理:

kotlin 复制代码
private var currentPrimaryItem: Fragment? = null

fun resumeFragment(position: Int) {
    if (position < 0 || position >= fragments.size) return
    val fragment = fragments[position]
    if (fragment.isAdded) {
        fragmentManager.beginTransaction()
            .setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
            .commitNow()
        currentPrimaryItem = fragment
        if (fragment is FlutterBoostFragment) {
            try {
                FlutterBoost.instance().plugin.onForeground()
            } catch (e: Exception) {
                // 忽略异常
            }
        }
    }
}

fun pauseFragment(position: Int) {
    if (position < 0 || position >= fragments.size) return
    val fragment = fragments[position]
    if (fragment.isAdded) {
        fragmentManager.beginTransaction()
            .setMaxLifecycle(fragment, Lifecycle.State.STARTED)
            .commitNow()
        if (fragment is FlutterBoostFragment) {
            try {
                FlutterBoost.instance().plugin.onBackground()
            } catch (e: Exception) {
                // 忽略异常
            }
        }
    }
}

fun setPrimaryItem(position: Int) {
    val newPrimaryItem = if (position in fragments.indices) fragments[position] else null
    if (currentPrimaryItem !== newPrimaryItem) {
        currentPrimaryItem?.takeIf { it.isAdded }?.let { pauseFragment(fragments.indexOf(it)) }
        newPrimaryItem?.takeIf { it.isAdded }?.let { resumeFragment(position) }
    }
}

优点:

  • 可以解决大部分闪烁问题,性能损失较小。

缺点:

  • 少部分页面可能仍会出现问题,需要进一步优化。

完全解决方案:通过微小滚动解决闪烁问题

适用场景:适用于所有页面,彻底解决闪烁问题。

解决方案: 通过在 Flutter 页面加载时进行微小的滚动(上下滑动一个像素),触发 Flutter 的渲染机制,从而避免闪烁问题。

示例代码:

dart 复制代码
bool _isScrollingUp = true; // 初始方向为向上滑动

void _scrollPageFixFlutterBoostBug({int attempt = 0}) {
    // 判断是否可以滑动
    bool canScrollUp = _scrollController.offset > 0;
    bool canScrollDown = _scrollController.position.maxScrollExtent > _scrollController.offset;

    if (_isScrollingUp && canScrollUp) {
        // 如果当前方向为向上滑动且可以向上滑动
        _scrollController.animateTo(
            _scrollController.offset - 1, // 向上滑动 1 个像素
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeInOut,
        );
    } else if (!_isScrollingUp && canScrollDown) {
        // 如果当前方向为向下滑动且可以向下滑动
        _scrollController.animateTo(
            _scrollController.offset + 1, // 向下滑动 1 个像素
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeInOut,
        );
    } else if (attempt < 2) {
        // 如果无法按当前方向滑动,则切换方向并递归调用,最多尝试 2 次
        _isScrollingUp = !_isScrollingUp;
        _scrollPageFixFlutterBoostBug(attempt: attempt + 1);
    } else {
        // 如果尝试了 2 次仍然无法滑动,停止尝试
        print("无法滑动,停止尝试");
    }
    // 切换方向,确保下次调用时滑动方向相反
    _isScrollingUp = !_isScrollingUp;
}

调用时机: 在页面显示时调用 _scrollPageFixFlutterBoostBug 方法,确保页面加载时触发微小滚动。

优点:

  • 彻底解决闪烁问题,适用于所有页面。
  • 性能影响极小,几乎可以忽略不计。

缺点:

  • 需要在页面加载时调用,可能需要在多个地方添加调用逻辑。

总结

通过上述分析和解决方案,开发者可以彻底解决 Android 集成 Flutter Boost 时页面闪烁的问题。临时方案一和临时方案二可以解决大部分问题,但可能会有性能损失或少部分页面仍出现问题。完全解决方案通过微小滚动触发 Flutter 的渲染机制,彻底解决了闪烁问题,且性能影响极小。

希望这些解决方案能帮助你在混合开发中实现更流畅、更稳定的用户体验。

相关推荐
张风捷特烈3 小时前
Flutter 百题斩#17 | SDK 组件数据入库 - sqlite
android·前端·flutter
猪哥帅过吴彦祖1 天前
Dart 如何直接调用 C 语言库
flutter
猪哥帅过吴彦祖1 天前
Flutter 与原生平台之间的通信
flutter
恋猫de小郭1 天前
聊聊 Flutter 在 iOS 真机 Debug 运行出现 Timed out *** to update 的问题
android·前端·flutter
火柴就是我2 天前
每日见闻之Flutter 怎么设置全局字体
android·flutter
江上清风山间明月2 天前
Flutter和Kotlin的对比
开发语言·flutter·kotlin
亿刀3 天前
为什么要学习Flutter编译过程
android·flutter
技术蔡蔡3 天前
Flutter和Firebae与单人聊天的简单实现(Firebase Realtime Database)
flutter·firebase
节省钱3 天前
【Flutter】深入理解 Provider:不仅仅是Consumer
开发语言·前端·flutter·前端框架