在扑朔迷离中,如何防止昂贵的子小部件多次重建?

时间:2020-01-27 23:22:18

标签: flutter

我有2个小部件。父级StatefulWidget在首次满载期间会多次更改状态,而子级StatelessWidget的构建成本很高。

构建子窗口小部件之所以昂贵,是因为它使用google_maps_flutter库,该库使用Web视图在屏幕上显示google地图。

如果可能,我希望此子窗口小部件中的build()函数仅执行一次。

但是,每当由于状态更改而多次构建父窗口小部件时,似乎子窗口小部件也将被多次构建。因此,当屏幕首次加载时,我会看到一些卡顿/滞后的情况。

防止子窗口小部件多次重建的最佳方法是什么?

下面是示例代码。

父小部件

class ParentWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
   Completer<GoogleMapController> _controller = Completer();
   LocationPosition _myPosition;

   @override
   void initState() {
     super.initState();
     initialize();
   }

   void initialize(){
     ....// other initialization logic which may call `setState()` multiple times
   }

   Set<Marker> getMarkers(){
     ....
   }

   @override
   Widget build(BuildContext context) {
     return Scaffold(body: GoogleMapWidget(_controller, _myPosition, getMarkers()));
   }
}

子窗口小部件

class GoogleMapWidget extends StatelessWidget {
  static const double ZOOM = 15;
  final Completer<GoogleMapController> _controller;
  final Set<Marker> markers;
  final LocationPosition _myPosition;
  GoogleMapWidget(this._controller, this._myPosition, this.markers);

  @override
  Widget build(BuildContext context) {
    print("Rebuilt"); // <-- This gets printed multiple times, which is not something I want.
    return GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: CameraPosition(
          target: LatLng(_myPosition.lat, _myPosition.lng),
          zoom: ZOOM,
        ),
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
        markers: markers);
  }
}

1 个答案:

答案 0 :(得分:0)

每次调用setState时,都会触发重建。在initState中调用它可能不是一个好主意。多次调用是不行的。

Importance of Calling SetState inside initState

为避免多次重建,

  • 在本地字段中初始化所有对象,只有当所有对象准备就绪时,才可以调用setState。

  • 除了在setState中设置变量外,请勿执行其他任何处理。

  • 不要在build方法中触发http / api调用。即使您是,也可以添加条件逻辑以仅在需要时这样做。

  • 在调用setState之前,您可能需要检查对象是否实际更改。

对于Google Maps包,尤其是Google Maps包,请检查MapController方法,因为您可能可以使用提供的方法,而无需设置小部件本身的属性。这样,谷歌地图包就可以确定是否需要setState。