iandis / isolated_worker

An isolated worker for Flutter (Isolate) and Web (Web Worker). Behaves almost the same as the compute function, except it is not a one-off worker.
MIT License
42 stars 11 forks source link

LateInitializationError: Field '_isolate@965339056' has not been initialized. #13

Closed ollyde closed 2 years ago

ollyde commented 2 years ago

When running the isolate for the first time it fails. Then all isolates afterwards succeed.

Looks like a library bug.


flutter: LateInitializationError: Field '_isolate@965339056' has not been initialized.
[ERROR:flutter[/lib/ui/ui_dart_state.cc]()(209)] Unhandled Exception: LateInitializationError: Field '_isolate@965339056' has not been initialized.
#0      IsolatedWorkerImpl._isolate (package:isolated_worker[/src/isolated_worker_default_impl.dart]())
package:isolated_worker/src/isolated_worker_default_impl.dart:1
#1      IsolatedWorkerImpl.close
package:isolated_worker/src/isolated_worker_default_impl.dart:181
#2      _compressImageInBackground
package:bap/…/files/compress_image.dart:156
#3      _Worker._runCallback
package:isolated_worker/src/isolated_worker_default_impl.dart:221
#4      _Worker._parentMessageReceiver
package:isolated_worker/src/isolated_worker_default_impl.dart:212 
iandis commented 2 years ago

Hi, @ollydixon

It looks like you're trying to close the IsolatedWorker immediately after calling run before giving it a chance to warm up.

However, I might be wrong, so could you please provide a minimal reproducible code?

Thanks.

ollyde commented 2 years ago

@iandis thank for you replying.

Sure, I'm doing image compression. Can't seem to figure out how to get the Web Worker to work with this one though. The docs don't tell me what to write inside them vs. what I have.

I reverted this back to Isolate, but it's the same code when I apply your library.

import 'dart:io'; import 'dart:isolate'; import 'dart:typed_data';

import 'package:bap/utils/files/helpers_files.dart';
import 'package:bap/utils/files/platform_file.dart';
import 'package:bap/utils/model_file_processing_options.dart';
import 'package:filesize/filesize.dart';
import 'package:flutter/foundation.dart';
import 'package:image/image.dart' as image_lib;

Future<CustomPlatformFile> compressImage(CustomPlatformFile platformFile) async {
  if (kIsWeb) {
    return _compressImageInBackground([null, platformFile]);
  }
  final p = ReceivePort();
  await Isolate.spawn(
    _compressImageInBackground,
    [p.sendPort, platformFile],
    errorsAreFatal: true,
  );
  return await p.first as CustomPlatformFile;
}

// Future<PlatformFile> _compressImageInBackground(PlatformFile platformFile, FileProcessingOptions options) async {
Future<CustomPlatformFile> _compressImageInBackground(List<Object?> arguments) async {
  try {
    final sendPort = arguments[0] as SendPort?;
    final platformFile = arguments[1] as CustomPlatformFile;

    final options = platformFile.fileProcessingOptons;

    // Not image
    if (!isImage(platformFile)) {
      if (sendPort == null) {
        return platformFile;
      }
      sendPort.send(platformFile);
      return Isolate.exit();
    }

    // Heic, server side compress.
    if (isHeic(platformFile)) {
      if (kDebugMode) {
        print("Cannot compress HEIC");
      }
      platformFile.fileProcessingOptons = FileProcessingOptions(
        clientOnlyUploadTrackingUid: options?.clientOnlyUploadTrackingUid,
        clientCompressed: false,
        clientResizedWidth: null,
        saveOriginalFile: true,
        compressImage: true,
        resizeImageWidth: options?.resizeImageWidth ?? 720,
      );
      if (sendPort == null) {
        return platformFile;
      }
      sendPort.send(platformFile);
      return Isolate.exit();
    }

    image_lib.Image? image;

    if (platformFile.bytes == null && !kIsWeb) {
      image = image_lib.decodeImage(await File(platformFile.path!).readAsBytes());
    } else {
      image = image_lib.decodeImage(platformFile.bytes!);
    }

    // Failed, so do it on the server.
    if (image == null) {
      if (kDebugMode) {
        print("Failed image compressing");
      }
      platformFile.fileProcessingOptons = FileProcessingOptions(
        clientOnlyUploadTrackingUid: options?.clientOnlyUploadTrackingUid,
        clientCompressed: false,
        clientResizedWidth: null,
        saveOriginalFile: true,
        compressImage: true,
        resizeImageWidth: options?.resizeImageWidth ?? 720,
      );
      if (sendPort == null) {
        return platformFile;
      }
      sendPort.send(platformFile);
      return Isolate.exit();
    }

    int originalLength = image.length;

    if (image.width > (options?.clientResizedWidth ?? 720)) {
      image = image_lib.copyResize(
        image,
        width: (options?.clientResizedWidth ?? 720),
        interpolation: image_lib.Interpolation.average,
      );
      if (kDebugMode) {
        print("Resized image");
      }
    }

    final compressedJgp = image_lib.encodeJpg(image, quality: 90);

    if (kDebugMode) {
      print("--- Compressing file ---");
      print("Input size : " + filesize(originalLength));
      print("Outpu size : " + filesize(image.length));
    }

    // Success.
    final platformFileNew = CustomPlatformFile(
      name: platformFile.name,
      size: compressedJgp.length,
      bytes: Uint8List.fromList(compressedJgp),
      fileProcessingOptons: FileProcessingOptions(
        clientOnlyUploadTrackingUid: options?.clientOnlyUploadTrackingUid,
        clientCompressed: true,
        clientResizedWidth: image.width,
        saveOriginalFile: false,
        compressImage: false,
        resizeImageWidth: null,
      ),
    );

    if (sendPort == null) {
      return platformFileNew;
    }
    sendPort.send(platformFileNew);
    return Isolate.exit();
  } catch (e) {
    if (kDebugMode) {
      print(e);
    }
    rethrow;
  }
}

And the supporting class


import 'dart:typed_data';

import 'package:bap/utils/model_file_processing_options.dart';
import 'package:file_picker/file_picker.dart';

class CustomPlatformFile extends PlatformFile {
  FileProcessingOptions? fileProcessingOptons;

  CustomPlatformFile({
    required String name,
    required int size,
    this.fileProcessingOptons,
    String? path,
    Uint8List? bytes,
  }) : super(
          name: name,
          size: size,
          bytes: bytes,
          path: path,
        );

  CustomPlatformFile.fromPlatformFile({
    required PlatformFile file,
    this.fileProcessingOptons,
  }) : super(
          name: file.name,
          size: file.size,
          bytes: file.bytes,
          path: file.path,
          identifier: file.identifier,
          readStream: file.readStream,
        );
}
iandis commented 2 years ago

Hi @ollydixon, from what I see, I think you were trying to close IsolatedWorker when your _compressImageInBackground fails. My suggestion is, don't close IsolatedWorker if you still need it running. However, I'll be patching this error in 0.1.1 as it should not throw error when calling close. Thanks!

ollyde commented 2 years ago

Thanks @iandis we're still figuring out how to get this working on Web hehe :-D

iandis commented 2 years ago

You need to create/import image compression API using javascript, then call it using JsIsolatedWorker @ollydixon

ollyde commented 2 years ago

@iandis ahh I though this converted the Dart code to JS automatically hehe.