【问题标题】:Function is only called once in page navigation函数在页面导航中只调用一次
【发布时间】:2020-08-11 19:18:27
【问题描述】:

我正在尝试编写一个从 Firebase 存储文件夹下载图像并将其显示在网格中的页面。当我第一次导航到此页面时,我对此没有任何问题。但是,一旦我导航到另一个页面,然后返回此页面,图像就不再加载。函数getImage() 用于加载图像。它被称为initState()。是不是因为它只在页面第一次打开时调用一次?

页面导航的代码sn-p如下:

class RouteGenerator {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    // Getting arguments passed in while calling Navigator.pushNamed
    final args = settings.arguments;

    switch (settings.name) {
...
 case '/stichpage':
        // Validation of correct data type
        return MaterialPageRoute(
          builder: (_) => ImagesScreen(),
        );
...  
}

这是页面的实际代码:

import 'package:flutter/material.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'dart:typed_data';
import 'dataholder.dart';

class ImagesScreen extends StatelessWidget {
  Widget makeImagesGrid() {
    return GridView.builder(
        itemCount: "objectname".length,
        gridDelegate:
            SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
        itemBuilder: (context, index) {
          return ImageGridItem(index);
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.lightBlue,
        elevation: 5,
        title: Text('Image Stitching'),
        centerTitle: true,
      ),
      body: Container(
        child: makeImagesGrid(),
      ),
      bottomNavigationBar: BottomAppBar(
        color: Colors.grey[200],
        child: Row(
          children: [
            Spacer(),
            IconButton(icon: Icon(Icons.save), onPressed: () {}),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        backgroundColor: Colors.lightBlue,
        foregroundColor: Colors.white,
        onPressed: () {},
        icon: Icon(Icons.burst_mode),
        label: Text('Stitch'),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }
}

class ImageGridItem extends StatefulWidget {
  int _index;

  ImageGridItem(int index) {
    this._index = index;
  }

  @override
  _ImageGridItemState createState() => _ImageGridItemState();
}

class _ImageGridItemState extends State<ImageGridItem> {
  Uint8List imageFile;
  StorageReference photosReference =
      FirebaseStorage.instance.ref().child("images");

  getImage() {
    if (!requestedIndexes.contains(widget._index)) {
      int maxSize = 7 * 1024 * 1024;
      photosReference
          .child("cell${widget._index}.png")
          .getData(maxSize)
          .then((data) {
        this.setState(() {
          imageFile = data;
        });
        imageData.putIfAbsent(widget._index, () {
          return data;
        });
      }).catchError((error) {
        debugPrint(error.toString());
      });
      requestedIndexes.add(widget._index);
    }
  }

  Widget decideGridTileWidget() {
    if (imageFile == null) {
      return Center(child: Text(""));
    } else {
      return Image.memory(
        imageFile,
        fit: BoxFit.cover,
      );
    }
  }

   @override
  void initState() {
    super.initState();
    if (!imageData.containsKey(widget._index)) {
      getImage();
    } else {
      this.setState(() {
        imageFile = imageData[widget._index];
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return GridTile(child: decideGridTileWidget());
  }
}

以及保存图像数据的代码:

import 'dart:typed_data';

Map<int, Uint8List> imageData = {};

List<int> requestedIndexes = [];

【问题讨论】:

  • 当您说“导航出去”时,您的意思是推送另一个视图?还是跳到上一个视图?
  • 推送到另一个视图。基本上是页面导航代码 sn-p 但不是'/stichpage' 它是'/dashboard'

标签: firebase flutter dart firebase-storage


【解决方案1】:

当您推送到另一个视图时,前一个视图保留在 Navigator 中,因此当您弹回它时,它会重建,但不会再次调用 initState

如果您想在弹出后屏幕恢复为主要屏幕时实际执行某些操作,您需要实现 RouteObserver 例如

final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();

class MyApp extends StatelessWidget {

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            theme: ThemeData(),
            navigatorObservers: [routeObserver],
            home: Screen1(),
            routes: {
                'screen2': (context) => Screen2(),
                'screen3': (context) => Screen3(),
            },
        );
     }
}

一旦你把它放在你的主屏幕上,你需要你的屏幕是RouteAware

class Screen3 extends StatefulWidget {
    @override
    _Screen3State createState() => _Screen3State(); 
}

class _Screen3State extends State<Screen3> with RouteAware {
    @override
    void didChangeDependencies() {
        super.didChangeDependencies();
        RouteObserverProvider.of(context).subscribe(this, ModalRoute.of(context));
     }

     @override
     void dispose() {
         RouteObserverProvider.of(context).unsubscribe(this);
         super.dispose();
     }

     @override
     void didPush() {
         print('didPush Screen3');
     }

     @override
     void didPopNext() {
         print('didPopNext Screen3');
     }
}

你真正需要的是didPopNext

David Anaya 在 Medium 上有一篇不错的帖子,您可以查找 here

【讨论】:

  • 这部分有效。图像仍然存在,但它们不会加载。因此,如果我要从 firebase 文件夹中删除一张照片,然后转到仪表板并返回,页面上的图像数量不会改变,即使应该少一张。
  • hm .. 不知道你是如何计算图像数量的,因为这是错误的itemCount: "objectname".length, 虽然它是虚拟代码(因为你使用的是固定的字符串长度)但是如果你真的在使用它,有你的问题。
  • 我认为itemCount 没有那么重要。当然,我可以将其更改为 10 之类的数字,但我只显示名称为 cell0.png、cell1.png、cell2.png、cell3.png 等的图像。在我的文件夹中,我有这四张照片,并且这就是它所显示的。但是,如果我删除了 cell3.png,转到仪表板并返回,cell3.png 仍然存在,即使它不应该存在。这就是问题所在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
相关资源
最近更新 更多