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

Store can not be opened from a background service when initialized from main thread, neither I am able to check if the store is open on given location. #699

Open
Chandio763 opened this issue Dec 5, 2024 · 7 comments
Labels
question How to do something/general question

Comments

@Chandio763
Copy link

Chandio763 commented Dec 5, 2024

I have searched existing issues

  • objectbox version: 4.0.3
  • Flutter/Dart version: 3.24.5
  • Build OS: Windows 11
  • Deployment OS or device: Android 12

Steps to reproduce

  1. Create a sample project or clone flutter_background_service example()
  2. Create a sample class and add objectbox dependencies and generate objectbox code.
  3. Initialize Object Box(openStore) in main method and inside onStart method of a background service, try to access that store. It will be null inside service(Isolates have different memory resources). If We try to open store on same location, it throws Exceptions "Bad state: failed to create store: Cannot open store: another store is still open using the same path". I want to use the same data to I have to access the same store.

### Expected behavior
If I am inside the background service. I should be able to openStore on that location to access data or I can get that opened store to perform operations. I should be able to perform operations on same store from UI thread and background service as well.

Actual behavior:

It throws error stating store is already opened.

Code

Please use example code of flutter background service

Things you maybe should also include:

  • My Entity Class

import 'package:objectbox/objectbox.dart';

@Entity()
class PrayerModel {
  @Id(assignable: true) // Allows manually assigned IDs for predefined prayers.
  int id = 0;
  String prayerName;
  String prayerText;
  String silentStartTime;
  String silentEndTime;
  String reminderTime;
  bool silentSwitchEnabled;
  bool reminderSwitchEnabled;
  PrayerModel({
    required this.id,
    required this.prayerName,
    required this.prayerText,
    required this.silentStartTime,
    required this.silentEndTime,
    required this.reminderTime,
    required this.silentSwitchEnabled,
    required this.reminderSwitchEnabled,
  });
  
  DateTime parseStringTime(String time, {bool forTomorrow = false}) {
  final now = DateTime.now();
  final parts = time.split(':');
  final hour = int.parse(parts[0]);
  final minute = int.parse(parts[1]);

  // Create DateTime for today or tomorrow
  return DateTime(
    now.year,
    now.month,
    now.day + (forTomorrow ? 1 : 0),
    hour,
    minute,
  );
}
  /// Utility to parse time strings back to `DateTime`
  DateTime parseTime(String time) => DateTime.parse(time);

  PrayerModel copyWith({
    int? id,
    String? prayerName,
    String? prayerText,
    String? silentStartTime,
    String? silentEndTime,
    String? reminderTime,
    bool? silentSwitchEnabled,
    bool? reminderSwitchEnabled,
  }) {
    return PrayerModel(
      id: id ?? this.id,
      prayerName: prayerName ?? this.prayerName,
      prayerText: prayerText ?? this.prayerText,
      silentStartTime: silentStartTime ?? this.silentStartTime,
      silentEndTime: silentEndTime ?? this.silentEndTime,
      reminderTime: reminderTime ?? this.reminderTime,
      silentSwitchEnabled: silentSwitchEnabled ?? this.silentSwitchEnabled,
      reminderSwitchEnabled: reminderSwitchEnabled ?? this.reminderSwitchEnabled,
    );
  }

  Map<String, dynamic> toMap() {
    final result = <String, dynamic>{};
  
    result.addAll({'id': id});
    result.addAll({'prayerName': prayerName});
    result.addAll({'prayerText': prayerText});
    result.addAll({'silentStartTime': silentStartTime});
    result.addAll({'silentEndTime': silentEndTime});
    result.addAll({'reminderTime': reminderTime});
    result.addAll({'silentSwitchEnabled': silentSwitchEnabled});
    result.addAll({'reminderSwitchEnabled': reminderSwitchEnabled});
  
    return result;
  }

  factory PrayerModel.fromMap(Map<String, dynamic> map) {
    return PrayerModel(
      id: map['id']?.toInt() ?? 0,
      prayerName: map['prayerName'] ?? '',
      prayerText: map['prayerText'] ?? '',
      silentStartTime: map['silentStartTime'] ?? '',
      silentEndTime: map['silentEndTime'] ?? '',
      reminderTime: map['reminderTime'] ?? '',
      silentSwitchEnabled: map['silentSwitchEnabled'] ?? false,
      reminderSwitchEnabled: map['reminderSwitchEnabled'] ?? false,
    );
  }

  String toJson() => json.encode(toMap());

  factory PrayerModel.fromJson(String source) => PrayerModel.fromMap(json.decode(source));

  @override
  String toString() {
    return 'PrayerModel(id: $id, prayerName: $prayerName, prayerText: $prayerText, silentStartTime: $silentStartTime, silentEndTime: $silentEndTime, reminderTime: $reminderTime, silentSwitchEnabled: $silentSwitchEnabled, reminderSwitchEnabled: $reminderSwitchEnabled)';
  }
}

My pubspec.yaml

name: khushu
description: A new Flutter project.
publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: '>=3.1.0 <4.0.0'

dependencies:
  flutter:
    sdk: flutter
  flutter_native_splash: ^2.4.1
  google_fonts: ^6.2.1
  flutter_svg: ^2.0.10+1
  flutter_qiblah: ^3.0.3
  sensors_plus: ^6.0.0
  permission_handler: ^11.3.1
  geolocator: ^13.0.2
  flutter_advanced_switch:
  provider: ^6.1.2
  geocoding: ^3.0.0
  shared_preferences: ^2.3.0
  flutter_background_service: ^5.0.10
  sound_mode: ^3.0.0
  flutter_local_notifications: ^18.0.1
  flutter_background_service_android: ^6.2.7
  double_tap_to_exit: ^1.0.1
  share_plus: ^10.0.0
  flutter_rating_bar: ^4.0.1
  # launch_review: ^3.0.1
  # android_alarm_manager_plus: ^4.0.4
  sqflite: ^2.3.3+1
  path: ^1.9.0
  syncfusion_flutter_pdf: ^27.2.5
  path_provider: ^2.1.4
  open_file: ^3.3.2
  url_launcher: ^6.3.0
  upgrader: ^11.3.0
  firebase_core: ^3.4.0
  firebase_analytics: ^11.3.0
  firebase_crashlytics: ^4.1.0
  onesignal_flutter: ^5.2.8
  mailer: ^6.1.2
  device_info_plus: ^11.1.1
  location: ^7.0.1
  # device_preview: ^1.2.0
  objectbox: ^4.0.3
  objectbox_flutter_libs:


dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^5.0.0
  objectbox_generator:
  build_runner:

flutter:
  uses-material-design: true

  assets:
    - assets/images/
    - assets/icons/
    - assets/icons/lt.svg
  fonts:
    - family: Poppins
      fonts:
        - asset: assets/fonts/Poppins-Regular.ttf
        - asset: assets/fonts/Poppins-Regular.ttf
          weight: 900

Logs
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Bad state: failed to create store: Cannot open store: another store is still open using the same path: "/data/data/com.prayer.khushu/app_flutter/obx-example" (OBX_ERROR code 10001)
E/flutter (17496): #0      ObjectBoxNativeError.throwMapped (package:objectbox/src/native/bindings/helpers.dart:74:9)
E/flutter (17496): #1      throwLatestNativeError (package:objectbox/src/native/bindings/helpers.dart:54:48)
E/flutter (17496): #2      checkObxPtr (package:objectbox/src/native/bindings/helpers.dart:31:5)
E/flutter (17496): #3      Store._checkStorePointer (package:objectbox/src/native/store.dart:451:7)
E/flutter (17496): #4      new Store (package:objectbox/src/native/store.dart:274:7)
E/flutter (17496): #5      openStore (package:khushu/objectbox.g.dart:91:14)
E/flutter (17496): #6      createStore (package:khushu/CommonFunctions/create_store.dart:13:16)
E/flutter (17496): <asynchronous suspension>
E/flutter (17496): #7      onStart (package:khushu/main.dart:207:13)
E/flutter (17496): <asynchronous suspension>
E/flutter (17496): 
@Chandio763 Chandio763 added the bug Something isn't working label Dec 5, 2024
@greenrobot-team
Copy link
Member

I just recently commented about this: #696 (comment)

Note: I labeled this issue with "more info required" so it will auto-close in a few days if there are no follow-up comments.

@greenrobot-team greenrobot-team added question How to do something/general question more info required Needs more info to become actionable. Auto-closed if no response. and removed bug Something isn't working labels Dec 9, 2024
@Chandio763
Copy link
Author

Chandio763 commented Dec 9, 2024

Tried using attach method inside a background service onStart method and it says,

ObjectBoxException` (ObjectBoxException: could not attach to the store at given path - please ensure it was opened before) store created

and If I try to open the store again, It gives can not open store error which I mentioned above.
Here is my code for open and attach store functions:

Future<Store> createStore() async {

    final docsDir = await getApplicationDocumentsDirectory();
    // Future<Store> openStore() {...} is defined in the generated objectbox.g.dart
    final st = openStore(directory: p.join(docsDir.path, "obx-example"));
    return st;
}

Future<Store> attachStore() async {
    // final storeRef = globalStore!.reference;
    final docsDir = await getApplicationDocumentsDirectory();
    return Store.attach(getObjectBoxModel(), p.join(docsDir.path, "obx-example") );
}

I called this create store method in main method and attach store method inside service onStart method.

@github-actions github-actions bot removed the more info required Needs more info to become actionable. Auto-closed if no response. label Dec 10, 2024
@greenrobot-team
Copy link
Member

greenrobot-team commented Dec 10, 2024

Thanks for the details! As it looks like Dart state is shared, maybe I jumped to conclusions and this background service does not actually run in a separate isolate, but the main isolate.

In that case, have you tried to make your code access the Store from a global variable and only initialize it in the main method, like in the examples?

@greenrobot-team greenrobot-team added the more info required Needs more info to become actionable. Auto-closed if no response. label Dec 10, 2024
@Chandio763
Copy link
Author

Chandio763 commented Dec 10, 2024

Yes, I have tried using a global variable. assign store to that variable in main method and when access that variable inside service onStart, variable have null value.

I can share the complete code in case you need it?

@github-actions github-actions bot removed the more info required Needs more info to become actionable. Auto-closed if no response. label Dec 11, 2024
@greenrobot-team
Copy link
Member

@Chandio763 Yes, a working code example is always more helpful! Anyhow, I have to look into how this background service package actually works to understand how to fix this.

@greenrobot-team greenrobot-team added the more info required Needs more info to become actionable. Auto-closed if no response. label Dec 11, 2024
Copy link

github-actions bot commented Jan 2, 2025

Without additional information, we are unfortunately not sure how to resolve this issue. Therefore this issue has been automatically closed. Feel free to comment with additional details and we can re-open this issue.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jan 2, 2025
@greenrobot-team
Copy link
Member

Reopening: while a code example is missing, it appears it is still useful to look into this use case.

@github-actions github-actions bot removed the more info required Needs more info to become actionable. Auto-closed if no response. label Jan 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question How to do something/general question
Projects
None yet
Development

No branches or pull requests

2 participants