Flutter different behaviour in debug vs release mode

Issue

I’m developing these features for a flutter app: loading an image from gallery, resize and save it.

The resizing part is a cpu intensive operation so I followed the approach suggested here using isolate to gain a better user experience.

When I run the code in debug mode I have no issue, but when I try the same code in release mode my image is saved in a wrong way.

Can someone help me to undestand the issue I explained please?

I test the code only on this device: HUAWEI P9 lite VNS-L31 with android 7.0

Here is the code to replicate the problem. This is a new flutter project with the following files:

In pubspec.yaml I add this section:

dependencies:
  path_provider: ^0.4.1
  image_picker: ^0.4.10
  image: ^2.0.4
  flutter:
    sdk: flutter

All code is in lib/main.dart:

import 'dart:async';
import 'dart:io';
import 'dart:isolate';

import 'package:flutter/material.dart';
import 'package:image/image.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  File _file;

  Future<File> _getImage() async {
    File image = await ImagePicker.pickImage(source: ImageSource.gallery);
    if (image != null) {
      return image;
    }
    return null;
  }

  static decode(DecodeParam param) async {
    var p = await param.file.readAsBytes();
    var image = decodeImage(p);
    var thumbnail = copyResize(image, 120);
    param.sendPort.send(thumbnail);
  }

  void _displayImage() async {
    setState(() {
      _file = null;
    });

    File file = await _getImage();
    ReceivePort receivePort = new ReceivePort();

    await Isolate.spawn(decode, new DecodeParam(file, receivePort.sendPort));

    var image = await receivePort.first;

    Directory tempDir = await getTemporaryDirectory();
    String tempPath = tempDir.path;

    File profilePictureFile =
        File(p.join(tempPath, 'thumbnail' + _counter.toString() + '.png'))
          ..writeAsBytesSync(encodePng(image));

    setState(() {
      _counter++;
      _file = profilePictureFile;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _file != null
                ? Container(
                    height: 200.0,
                    width: 200.0,
                    decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        image: DecorationImage(
                            fit: BoxFit.fitWidth, image: FileImage(_file))))
                : Container(),
          ],
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _displayImage,
        child: new Icon(Icons.add),
      ),
    );
  }
}

class DecodeParam {
  final File file;
  final SendPort sendPort;
  DecodeParam(this.file, this.sendPort);
}

flutter doctor -v:

[√] Flutter (Channel master, v0.9.7-pre.61, on Microsoft Windows [Versione 10.0.15063], locale it-IT)
    • Flutter version 0.9.7-pre.61 at C:\src\flutter
    • Framework revision 2d81adf74c (2 days ago), 2018-10-05 22:29:37 -0700
    • Engine revision 572fa5646a
    • Dart version 2.1.0-dev.6.0.flutter-c6254163dc

[√] Android toolchain - develop for Android devices (Android SDK 28.0.1)
    • Android SDK at d:\Profiles\alarosa\AppData\Local\Android\sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.1
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b02)
    • All Android licenses accepted.

[√] Android Studio (version 3.1)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 26.0.1
    • Dart plugin version 173.4700
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b02)

[!] IntelliJ IDEA Community Edition (version 2018.1)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.1
    X Flutter plugin not installed; this adds Flutter specific functionality.
    X Dart plugin not installed; this adds Dart specific functionality.
    • For information about installing plugins, see
      https://flutter.io/intellij-setup/#installing-the-plugins

[√] VS Code (version 1.27.2)
    • VS Code at d:\Profiles\alarosa\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 2.19.0

[√] VS Code, 64-bit edition (version 1.27.2)
    • VS Code at C:\Program Files\Microsoft VS Code
    • Flutter extension version 2.19.0

[√] Connected device (1 available)
    • HUAWEI VNS L31 • 4TE0216A14001341 • android-arm64 • Android 7.0 (API 24)

! Doctor found issues in 1 category.

Solution

Following @GunterZochbauer suggestion I opened an issue on flutter repository.

Flutter team is working on it, and, as you can read on github thread, Jason-Simmons suggest the following work around.

Change the sender to:

param.sendPort.send([thumbnail.width, thumbnail.height, thumbnail.data]);

and the receiver to:

List<dynamic> imageData = await receivePort.first;
var image = new Image.fromBytes(imageData[0], imageData[1], imageData[2]);

Answered By – ilBarra

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.