jjzjj

image - Flutter Navigation 和同时对 dispose() 的要求

coder 2023-07-23 原文

尝试使用 image_picker在 Flutter 中,我遇到以下问题:

当导航应该返回到 Widget Nr1 时,我无法再在 Widget Nr1 中调用 setState()。这是因为当 Navigation.push 从 Widget-Nr1 到 Widget-Nr2 时调用了 dispose() 方法。

事实证明,我绝对需要调用此 dispose() 方法才能使 image_picker 插件正常工作。 (如果我不这样做,那么错误 ...was disposed with an active Ticker... 发生,可能是由于 image_picker 插件在迫切需要预先处理()的引擎盖。

反正我是蛇咬尾部的感觉。

作为总结,我执行以下操作(另请参见下面的代码):

  • 在 Widget Nr1 内部:按下 FloatingAction-Button,将导航器推送到 Widget Nr2
  • 两个小部件(Nr1 和 Nr2)都是有状态的小部件
  • 它们都有一个 dispose-method(需要否则 image_picker 不起作用)
  • Widget-Nr2 调用 image_picker 插件(让用户用相机拍照并要求用户提供一些描述图像的字符串文本)
  • 结果(即图像文件和一些字符串文本)需要返回给 Widget-Nr1(使用 Navigation.pop)
  • Widget-Nr1 实际上确实获取了这些数据(即图像加上一些字符串文本)
  • 但是:在 Navigation.pop 之后它不能再调用 setState() 很可能是因为两个 Widget 都已经调用了它们的 dispose() 方法

我在 Widget-Nr1 中得到错误:

Dart Error: Unhandled exception:
setState() called after dispose()

我该怎么做才能完成这项工作?

如何在 Widget-1 中再次使用 image_picker 的结果数据(在 Widget-1 中需要 dispose())作为 Navigation.pop 结果这在所有导航之后 setState() 仍然可行的方式 ??

或者还有其他方法可以使用吗?

这是我的代码:

StatefulWidget Nr1(摘录):

    child: FloatingActionButton(
      onPressed: () async {
        _imagePickerResult = await navigateToImagePicker(context);
        setState(() async {
            this.itemBins.add(ItemBin(
                _imagePickerResult.locationName,
                _imagePickerResult.locationImage));
        });
      },
      child: Icon(Icons.add),
    ),

    // ...

    Future<ImagePickerResult> navigateToImagePicker(BuildContext context) async {
      return await Navigator.push(
        context, MaterialPageRoute(builder: (context) => MyImagePickerView())
      );
    }

    // ...

    class ImagePickerResult {
      String locationName;
      Image locationImage;

      ImagePickerResult({this.locationName, this.locationImage});
    }

StatefulWidget Nr2:

    import 'package:flutter/material.dart';
    import 'dart:io';
    import 'package:image_picker/image_picker.dart';
    import './../../models/image_picker_location.dart';

    class MyImagePickerView extends StatefulWidget {
      _MyImagePickerViewState createState() => _MyImagePickerViewState();
    }

    class _MyImagePickerViewState extends State<MyImagePickerView> {
      TextEditingController _myController = TextEditingController();
      File _imageFile;
      bool _pickImage = true;

      @override
      Widget build(BuildContext context) {
        if (_pickImage) {
          return FutureBuilder<File>(
            future: ImagePicker.pickImage(source: ImageSource.camera),
            builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
              if (snapshot.hasData) {
                _pickImage = false;
                _imageFile = snapshot.data;
                return _showImage(snapshot.data);
              } else {
                return Scaffold(
                  body: Center(
                    child: Text('no image picker availalbe'),
                  ),
                );
              }
            },
          );
        } else {
          return _showImage(_imageFile);
        }
      }

      Widget _showImage(File imgFile) {
        return Scaffold(
          body: Stack(
            alignment: AlignmentDirectional.topStart,
            children: <Widget>[
              Positioned(
                left: 0.0,
                bottom: 0.0,
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height,
                child: Center(
                  child: imgFile == null
                      ? Text('No image selected.')
                      : Image.file(imgFile),
                ),
              ),
              Positioned(
                left: 16.0,
                bottom: 70.0,
                width: MediaQuery.of(context).size.width - 32.0,
                height: 50.0,
                child: Container(
                  color: Colors.grey[100],
                  child: TextField(
                    autofocus: false,
                    keyboardType: TextInputType.text,
                    autocorrect: false,
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: 22.0,
                        fontWeight: FontWeight.w600),
                    decoration: InputDecoration(
                      hintStyle: TextStyle(
                          color: Colors.black38,
                          fontSize: 22.0,
                          fontWeight: FontWeight.normal),
                      hintText: "depart From :",
                      contentPadding: const EdgeInsets.fromLTRB(6.0, 13.0, 0, 12.0),
                      enabledBorder: UnderlineInputBorder(
                        borderSide: BorderSide(color: Colors.red, width: 2.0),
                      ),
                    ),
                    maxLines: 1,
                    textAlign: TextAlign.left,
                    controller: _myController,
                    onEditingComplete: () {
                      FocusScope.of(context)
                          .requestFocus(FocusNode()); // dismiss keyboard
                      Navigator.pop(
                        context,
                        ImagePickerResult(
                          locationName: _myController.text,
                          locationImage: Image.file(imgFile),
                        ),
                      );
                    },
                  ),
                ),
              ),
            ],
          ),
        );
      }
    }

Widget Nr1 的处理方法:

  @override
  void dispose() {
    if (_debounce?.isActive ?? false) {
      _debounce.cancel(); // if _debounce is active cancel it...
    }
    _debounce = Timer(const Duration(milliseconds: 200), () {
      // security wait due to the fact that there are animations still running during setState()
    });
    // dispose AnimationController
    controller.dispose();
    _debounce.cancel();
    super.dispose();
  }

Widget-Nr2的dispose方法:

   @override
   void dispose() {
     _myController.dispose();
     super.dispose();
   }

如果我不让 view1 在 image_picker 启动之前执行 dispose(),则会出现错误消息... ) 在 image_picker 的 segue 发生之前人工“等待”200 毫秒)...

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown while finalizing the widget tree:
flutter: _HistoryViewState#a8eac(ticker active but muted) was disposed with an active Ticker.
flutter: _HistoryViewState created a Ticker via its SingleTickerProviderStateMixin, but at the time dispose()
flutter: was called on the mixin, that Ticker was still active. The Ticker must be disposed before calling
flutter: super.dispose(). Tickers used by AnimationControllers should be disposed by calling dispose() on the
flutter: AnimationController itself. Otherwise, the ticker will leak.
flutter: The offending ticker was: Ticker(created by _HistoryViewState#a8eac(lifecycle state: created))
flutter: The stack trace when the Ticker was actually created was:
flutter: #0      new Ticker.<anonymous closure> 
package:flutter/…/scheduler/ticker.dart:64
flutter: #1      new Ticker 
package:flutter/…/scheduler/ticker.dart:66
flutter: #2      __HistoryViewState&State&SingleTickerProviderStateMixin.createTicker 
package:flutter/…/widgets/ticker_provider.dart:93
flutter: #3      new AnimationController 

最佳答案

代替 setState(() {...}),尝试 if (mounted) { setState(() {...}) } 代码可能在用户导航离开后运行。

关于image - Flutter Navigation 和同时对 dispose() 的要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54599561/

有关image - Flutter Navigation 和同时对 dispose() 的要求的更多相关文章

  1. ruby - 使用 postgres.app 在 rvm 下要求 pg 时出错 - 2

    我正在使用Postgres.app在OSX(10.8.3)上。我已经修改了我的PATH,以便应用程序的bin文件夹位于所有其他文件夹之前。Rammy:~phrogz$whichpg_config/Applications/Postgres.app/Contents/MacOS/bin/pg_config我已经安装了rvm并且可以毫无错误地安装pggem,但是当我需要它时我得到一个错误:Rammy:~phrogz$gem-v1.8.25Rammy:~phrogz$geminstallpgFetching:pg-0.15.1.gem(100%)Buildingnativeextension

  2. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  3. ruby-on-rails - Rails - Carrierwave 进程抛出 ArgumentError : no images in this image list - 2

    在尝试实现应用auto_orient的过程之后!对于我的图片,我收到此错误:ArgumentError(noimagesinthisimagelist):app/uploaders/image_uploader.rb:36:in`fix_exif_rotation'app/controllers/posts_controller.rb:12:in`create'Carrierwave在没有进程的情况下工作正常,但在添加进程后尝试上传图像时抛出错误。流程如下:process:fix_exif_rotationdeffix_exif_rotationmanipulate!do|image|

  4. ruby-on-rails - Nokogiri 要求 Ruby 版本 < 2.3 - 2

    我正在尝试让Rails在Windows10上运行。我正在使用Ruby2.3.0和Rails4.2.6,并且暂时使用Nokogiri1.6.3。当我尝试运行railsnewdemo时,它返回错误:Anerroroccurredwhileinstallingnokogiri(1.6.7.2),andBundlercannotcontinue.Makesurethat`geminstallnokogiri-v'1.6.7.2'`succeedsbeforebundling.当我运行geminstallnokogiri-v'1.6.7.2时,我得到:ERROR:Errorinstallingn

  5. ruby - 根据要求使用特定的 VCR 磁带 - 2

    情况:使用Rspec、FactoryGirl和VCR测试Rails应用程序。每次创建用户时,都会通过Stripe的API创建关联的Stripe客户。测试时,添加VCR.use_cassette或describe"...",vcr:{cassette_name:'stripe-customer'}do...到涉及用户创建的每个规范。我的实际解决方案如下:RSpec.configuredo|config|config.arounddo|example|VCR.use_cassette('stripe-customer')do|cassette|example.runendendend但这是

  6. ruby - 两个 gem 共享相同的要求? - 2

    当我打电话时:require'retryable'这两个gem冲突:https://github.com/robertsosinski/retryablehttps://github.com/carlo/retryable因为他们都有一个“可重试”文件,所以他们要求用户要求。我对使用第一个gem很感兴趣,但这并不总是会发生。这段代码作为我自己的gem的一部分执行,它必须对所有用户都是可靠的。有没有办法从gem中专门要求(因为gem名称当然不同)?如何解决这个命名冲突?编辑:澄清一下,这是官方仓库,gem名称实际上是不同的(“retryable-rb”和“carlo-retryable”

  7. ruby - 当我已经在使用 %r 时,为什么 rubocop 要求我放置//围绕正则表达式? - 2

    我有以下正则表达式regexp=%r{((returned|undelivered)\smail|mail\sdelivery(\sfailed)?)}x但是当我在上面运行rubocop时,它会提示我需要“在正则表达式周围使用//”。我怎样才能绕过它? 最佳答案 您可以通过将.rubocop.yml文件添加到项目文件夹的根目录并设置适当的配置来禁用(和启用)任何rubocopcop。要查看您可以做什么,请查看rubocop包中的全局default.yml。它有完整的评论。对于这个特殊问题,创建一个.rubocop.yml和...要完

  8. ruby - 由于 GEM_HOME 的要求,启动 Ruby 应用程序非常慢 - 2

    我目前正在开发一个ruby​​应用程序,但它运行得非常(非常!)慢..到目前为止,我已经尝试了几件事,我可以将其缩小到主要问题:Ruby正在尝试在$LOAD_PATH的每个目录中查找它的需求。基本上我所观察到的是,ruby正在查看大量文件,试图查看那里是否存在需求。如果找不到它们,它将转到下一个目录。好消息是我可以通过strace看到这种情况。有很多这样的输出:open("/boa_proj_build/nsteen/.gem/gems/i18n-0.7.0/lib/commander/help_formatters/base.rb",O_RDONLY|O_CLOEXEC)=-1ENO

  9. ruby - 为什么 rvm install 2.0.0 要求输入 sudo 密码? - 2

    我正在尝试通过rvm安装ruby​​2.0.0-p247。但是,它要求输入密码。提供sudo密码正常吗?我没有在sudoers文件中配置sudo密码。我正在使用OracleEnterpriseLinux6x64。 最佳答案 sudo用于autolibs-这意味着RVM将安装所需的软件,如openssh或libyaml,这是标准ruby​​正常工作所必需的。您可以更改autolibs以查看所需的包而不是安装它们:rvmautolibsread-fail并恢复到安装要求的默认设置:rvmautolibsreset

  10. ruby-on-rails - 带有选项的 link_to image_tag (rel, title) - 2

    在HTML中我会写:但我必须针对ruby​​onrails对其进行调整,而且我对它还很陌生...所以我尝试了:rel="lightbox"title="mycaption">...但它不起作用,因为“rel="lightbox"title="mycaption">”部分未应用但出现在html部分上+我看到了2个图像,而我应该只看到“imagethumb”。我也试过:"lightbox",:title=>"mycaption")%>我也看到了这两张图...我应该怎么做才能获得与我编写的HTML代码等效的内容? 最佳答案 试试这个"")

随机推荐