Flutter: 消除rebuild,提升性能🚀

1,112 阅读2分钟

本方案已废弃,点击查看新方案

关于MediaQuery引起rebuild的原因及解决方案,可参考京东云团队# Flutter调优--深入探究MediaQuery引起界面Rebuild的原因及解决办法 | 京东云技术团队

那么为什么要有本文,因为上文中给出的解决方案在3.10.2版本中,并不起效。

针对上文中给出的方案:

一、useInheritedMediaQuery
  'useInheritedMediaQuery' is deprecated and shouldn't be used.
   Remove this parameter as it is now ignored.
   Material App never introduces its own MediaQuery; the View widget takes care of that.
   This feature was deprecated after v3.7.0-29.0.pre.

在3.10.2中,加入该属性后,出现上面的提示,按照这段提示,3.7.0版本中就已经废弃该属性。

二、使用Builder控件包裹
经实际测试,也并未生效。

我的思路是,在顶层获取状态栏高度、屏幕宽高,存入常量中,后续页面调用所需常量即可。

代码如下:

@override
Widget build(BuildContext context) {
  //该方案部分安卓机型会出现丢失问题,可参考新文章
  
  Constants.initializeScreenConstants(context);
  
  return MaterialApp.router(
      debugShowCheckedModeBanner: false,
      title: '小火箭',
      routerConfig: router(), 
      builder: EasyLoading.init(),
    ),
  );
}

对应Constants.dart

import 'package:flutter/material.dart';

class Constants {

  static late double stateHeight;
  static late double screenHeight;
  static late double screenWidth;

  static void initializeScreenConstants(BuildContext context){
    //使用 MediaQueryData.fromView(View.of(context))
    //不要用 MediaQuery.sizeOf(context)
    //这两者是有区别的
    //In a utility class or a custom function,要使用MediaQueryData.fromView(View.of(context)).
    var currentView = MediaQueryData.fromView(View.of(context));
    stateHeight = currentView.padding.top;
    screenWidth = currentView.size.width;
    screenHeight = currentView.size.height;
  }
}

引用时,只需调用Constants.stateHeight即可,记得要引入Constants.dart

通过将调用MediaQuery的操作前置,避免了在UI组件中调用MediaQuery,达到消除rebuild的目的,包括键盘弹出引起的rebuild问题,因为UI组件中已经没有MediaQuery的地方。

关于键盘弹出,引起rebuild问题

在调研过程中,发现将输入框直接包裹在GestureDetector中,并添加behavior属性,将其置为HitTestBehavior.opaque,也可以解决rebuild问题。代码如下:

GestureDetector(behavior:HitTestBehavior.opaque,child:TextField(),);

总结

大胆假设,小心求证,不断调整,快速迭代。