Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_send is somehow destroying additional field in Computer #4

Open
Ben1980 opened this issue Feb 27, 2024 · 6 comments · May be fixed by #5
Open

_send is somehow destroying additional field in Computer #4

Ben1980 opened this issue Feb 27, 2024 · 6 comments · May be fixed by #5
Labels
question Further information is requested

Comments

@Ben1980
Copy link

Ben1980 commented Feb 27, 2024

I'm currently working on BLE support. Because of that, I needed to extend Computer with the additional field BluetoothDevice? device. The problem starts when calling download via download, afterward the object computer no longer contains a valid BluetoothDevice object. All other fields are fine.

@override
  Future<List<Dive>> download(
    Computer computer,
    ComputerTransport transport, [
    String? lastFingerprint,
  ]) async {
    await _send((
      DiveComputerMethod.download,
      [computer, transport, lastFingerprint],
    ));
    return (_downloadedDives = Completer()).future;
  }
class Computer {
  Computer(
    this.vendor,
    this.product, {
    this.transports = const [],
  });

  final String vendor, product;
  final List<ComputerTransport> transports;
  BluetoothDevice? device;

  void addBleDevice(BluetoothDevice device) {
    this.device = device;
  }

  @override
  String toString() =>
      '$vendor $product ${device ?? ''} [${transports.map((t) => t.name).join(', ')}]';

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Computer &&
          runtimeType == other.runtimeType &&
          vendor == other.vendor &&
          product == other.product;

  @override
  int get hashCode {
    // hash codes are not equal across isolates, so we need to generate a
    // consistent hash code for each computer
    return '$vendor $product'.codeUnits.fold(1, (a, b) => a * b);
  }
}
@Ben1980 Ben1980 changed the title _send is somehow destroying addition fiel in Computer _send is somehow destroying additional field in Computer Feb 28, 2024
@Sese-Schneider
Copy link
Member

Sese-Schneider commented Feb 28, 2024

@Ben1980 I think its an issue on how Isolates transfer objects.

You either have to make the BluetoothDevice final or make sure it can be serialized.

If this doesn't work I suggest caching the object on the isolate site and only passing an identifier, and retrieving from cached objects when the identifier is passed back.


Isolates in Dart can transfer objects between them, but with some limitations:

  1. Primitive data types and built-in objects: These types (e.g., integers, strings, lists, maps) are transferred directly without any modifications.
  2. Custom objects:
    • Final fields: These fields are serialized and transferred to the receiving isolate, maintaining their values.
    • Non-final fields: Due to serialization and deserialization during the transfer process, their values of final fields might not be preserved if they:
      • Contain references to mutable objects: The references themselves are transferred, but the actual objects might not be, potentially leading to unexpected behavior.
      • Implement custom serialization logic: If the class defines its own toJson or other serialization methods, those methods will be used, and the resulting representation might not include all non-final fields.

There are a few more limitations, read here.

@Sese-Schneider Sese-Schneider added the question Further information is requested label Feb 28, 2024
@Ben1980
Copy link
Author

Ben1980 commented Feb 28, 2024

You're right, i think as well this is the issue. BluetoothDevice is a foreign class from flutter_blue_plus unfortunately so I will need to got the caching way. Do you have any hint or suggestion how to do it? Otherwise I would utilize shared_preferences.

@Sese-Schneider
Copy link
Member

Sese-Schneider commented Feb 28, 2024

@Ben1980 first you should try making the field final in Computer.
But if the object contains more non-final children this will not work.

I wouldn't go with shared preferences or any persistent caches, but instead a normal memory cache.
First make sure the objects are comparable (hashCode and equality implemented), then just create a HashMap with the objects hashCode as key.
Forward the hashcode to the non-isolate layer, and when getting it back try to read the object back from the memory cache.

@Ben1980
Copy link
Author

Ben1980 commented Feb 28, 2024

How would you do that for a foreign class of another plugin like BluetoothDevice? As far as I can see it is not providing a proper hashCode nor equality function. I've never used a memory cache, do you have any examples?

@Sese-Schneider
Copy link
Member

@Ben1980 I think it does implement the required equality functions!

https://github.com/boskokg/flutter_blue_plus/blob/9381858018ae448b7c9e1ac6f1b621d2db240439/lib/src/bluetooth_device.dart#L667-L673

So what you can do now is the following:

final bluetoothDeviceCache = Map<int, BluetoothDevice>();

/// Function returns a hashCode which can be used to retrieve the BluetoothDevice
int storeBluetoothDevice(BluetoothDevice device) {
  bluetoothDeviceCache[device.hashCode] = device;
  return device.hashCode;
}

/// Function returns a BluetoothDevice based on its hashCode.
BluetoothDevice? getBluetoothDevice(int hashCode) {
  return bluetoothDeviceCache[hashCode];
}

now just pass the hashCode int receved from storeBluetoothDevice to the main layer and back to the isolate.

@Ben1980
Copy link
Author

Ben1980 commented Feb 29, 2024

Ok currently i don't know how to solve thisproblem. I tried passing BluetoothDevice to the isolate but tht seems not compatible because i don't get a proper object. I also tried the caching idea but also there i'm not sure how to go on because the isolate doesn't share memory. I think a call would help, you know more about flutter/dart so you probably know what to do.

@Sese-Schneider Sese-Schneider linked a pull request Mar 11, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants