isar / hive

Lightweight and blazing fast key-value database written in pure Dart.
Apache License 2.0
4.02k stars 399 forks source link

Issue with openBox and typeAdapters #543

Open tonileppanen opened 3 years ago

tonileppanen commented 3 years ago

I noticed an old closed ticket about the same subject so I opened a new one. My issue is at next comment.

Getting the same error again. Here is the stacktrace:

_CastError
type '_OneByteString' is not a subtype of type 'int' in type cast
user.g.dart in UserAdapter.read at line 17
binary_reader_impl.dart in BinaryReaderImpl.read at line 321
binary_reader_impl.dart in BinaryReaderImpl.readFrame at line 266
frame_helper.dart in FrameHelper.framesFromBytes at line 16
frame_io_helper.dart in FrameIoHelper.framesFromFile at line 37
Called from: <asynchronous suspension>
storage_backend_vm.dart in StorageBackendVm.initialize at line 74
Called from: <asynchronous suspension>
box_base_impl.dart in BoxBaseImpl.initialize at line 82
hive_impl.dart in HiveImpl._openBox at line 95
Called from: <asynchronous suspension>
hive_impl.dart in HiveImpl.openBox at line 112
main.dart in main._openBoxes at line 30
Called from: <asynchronous suspension>
main.dart in main at line 42
Called from: async_patch.dart in _AsyncAwaitCompleter.start
main.dart in main at line 20
Called from: hooks.dart in _runMainZoned.<fn>.<fn>

This is what I do in main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  Future _openBoxes() async {
    await Hive.initFlutter();
    return Future.wait([
      Hive.openBox('user'),
      Hive.openBox('submenu'),
    ]);
  }

  Hive.registerAdapter(UserAdapter(), 1);
  Hive.registerAdapter(SubMenuAdapter(), 2);
  Hive.registerAdapter(MenuTypeAdapter(), 3);
  await _openBoxes();

  runApp(
    ChangeNotifierProvider(
      create: (context) => AuthProvider()..init(),
      child: Oregon(),
    ),
  );
}

User class:

@HiveType()
class User extends HiveObject {
  @HiveField(0)
  int userId;
  @HiveField(1)
  int driverId;
  @HiveField(2)
  String name;
  @HiveField(3)
  String email;
  @HiveField(4)
  String password;
  @HiveField(5)
  String authToken;

  @HiveField(6)
  String gsm;
  @HiveField(7)
  String avatarUrl;

  @HiveField(8)
  String timeZone;
  @HiveField(9)
  String locale;
  @HiveField(10)
  String language;

  User({
    this.userId,
    this.driverId,
    this.name,
    this.email,
    this.password,
    this.authToken,
    this.gsm,
    this.timeZone,
    this.locale,
    this.language,
    this.avatarUrl,
  });
}

auto generated UserAdapter: The corresponding line in stacktrace for this file is

userId: fields[0] as int

class UserAdapter extends TypeAdapter<User> {
  @override
  User read(BinaryReader reader) {
    var numOfFields = reader.readByte();
    var fields = <int, dynamic>{
      for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return User(
      userId: fields[0] as int,
      driverId: fields[1] as int,
      name: fields[2] as String,
      email: fields[3] as String,
      password: fields[4] as String,
      authToken: fields[5] as String,
      gsm: fields[6] as String,
      timeZone: fields[8] as String,
      locale: fields[9] as String,
      language: fields[10] as String,
      avatarUrl: fields[7] as String,
    );
  }

  @override
  void write(BinaryWriter writer, User obj) {
    writer
      ..writeByte(11)
      ..writeByte(0)
      ..write(obj.userId)
      ..writeByte(1)
      ..write(obj.driverId)
      ..writeByte(2)
      ..write(obj.name)
      ..writeByte(3)
      ..write(obj.email)
      ..writeByte(4)
      ..write(obj.password)
      ..writeByte(5)
      ..write(obj.authToken)
      ..writeByte(6)
      ..write(obj.gsm)
      ..writeByte(7)
      ..write(obj.avatarUrl)
      ..writeByte(8)
      ..write(obj.timeZone)
      ..writeByte(9)
      ..write(obj.locale)
      ..writeByte(10)
      ..write(obj.language);
  }
}

Do you think this is related to Hive?

Originally posted by @selimkundakci in https://github.com/hivedb/hive/issues/214#issuecomment-589606229

tonileppanen commented 3 years ago

I am facing this same issue now. Got any idea what is it related to?

type '_OneByteString' is not a subtype of type 'int' in type cast

This started to occur on few devices (Galaxy A8 and Oneplus 7 Pro) after delete and reinstall of the app. I have been using only the latest version v1.4.1+1

I have nested TypeAdapters in one box that I am trying to open:

var box = await Hive.openBox<Week>("weekBox");

_CastError: type '_OneByteString' is not a subtype of type 'int' in type cast
  File "day.g.dart", line 21, in DayAdapter.read
  File "binary_reader_impl.dart", line 325, in BinaryReaderImpl.read
  File "binary_reader_impl.dart", line 212, in BinaryReaderImpl.readMap
  File "binary_reader_impl.dart", line 316, in BinaryReaderImpl.read
  File "week.g.dart", line 17, in WeekAdapter.read
  File "binary_reader_impl.dart", line 325, in BinaryReaderImpl.read
  File "binary_reader_impl.dart", line 273, in BinaryReaderImpl.readFrame
  File "frame_helper.dart", line 17, in FrameHelper.framesFromBytes
  File "frame_io_helper.dart", line 41, in FrameIoHelper.framesFromFile
  File "<asynchronous suspension>"
  File "storage_backend_vm.dart", line 82, in StorageBackendVm.initialize
  File "<asynchronous suspension>"
  File "hive_impl.dart", line 106, in HiveImpl._openBox
  File "<asynchronous suspension>"
  File "hive_impl.dart", line 135, in HiveImpl.openBox
  File "<asynchronous suspension>"
@HiveType(typeId: 0)
class Week extends HiveObject {
  @HiveField(0)
  String weekNumber;

  @HiveField(1)
  Map<String, Day> weekDays;
class WeekAdapter extends TypeAdapter<Week> {
  @override
  final int typeId = 0;

  @override
  Week read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return Week(
      weekNumber: fields[0] as String,
      weekDays: (fields[1] as Map)?.cast<String, Day>(),
    );
  }

  @override
  void write(BinaryWriter writer, Week obj) {
    writer
      ..writeByte(2)
      ..writeByte(0)
      ..write(obj.weekNumber)
      ..writeByte(1)
      ..write(obj.weekDays);
  }

  @override
  int get hashCode => typeId.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is WeekAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}
@HiveType(typeId: 1)
class Day {
  @HiveField(0)
  String text;

  @HiveField(1)
  int value;
class DayAdapter extends TypeAdapter<Day> {
  @override
  final int typeId = 1;

  @override
  Day read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return Day(
      text: fields[0] as String,
      value: fields[1] as int,
    );
  }

Version

tonileppanen commented 3 years ago

I added subfolder-attribute for initFlutter-function, released a new version and tried again with Oneplus 7 Pro.

void main() async {
  Hive
    ..initFlutter("flutterfiles")
    ..registerAdapter(DayAdapter())
    ..registerAdapter(WeekAdapter());

    ...
}

The app was working once, but after remove and reinstall of the app the issue reoccured.

type '_OneByteString' is not a subtype of type 'int' in type cast

Could it be that the database file is not deleted when removing the app from phone and there's something else left that shouldn't be there?

jchirinosodio commented 3 years ago

Hey there having the same issue with some few android devices, I noticed that If I try to install an old version of the app from the App Store and then updating it using an APK(the one causing issues) it works.

But if I try installing the app from scratch it does not, I feel like something is being left behind the scenes after deleting the app.

image

This is complaining about this model:

image

jchirinosodio commented 3 years ago

I added subfolder-attribute for initFlutter-function, released a new version and tried again with Oneplus 7 Pro.

void main() async {
  Hive
    ..initFlutter("flutterfiles")
    ..registerAdapter(DayAdapter())
    ..registerAdapter(WeekAdapter());

    ...
}

The app was working once, but after remove and reinstall of the app the issue reoccured.

type '_OneByteString' is not a subtype of type 'int' in type cast

Could it be that the database file is not deleted when removing the app from phone and there's something else left that shouldn't be there?

did you had any luck at the end on this? :/ I am thinking of using something else.. this is a major issue for me.

tonileppanen commented 3 years ago

I got rid of this error. I wish I had tested and documented this properly, but I couldn't reproduce this on my own devices. It probably had something to do with having extra initialization for Hive. Or initing Hive too late.

At least do not use this:

final appDocumentDir = await getApplicationDocumentsDirectory(); ..init(appDocumentDir.path)

jchirinosodio commented 3 years ago

I got rid of this error. I wish I had tested and documented this properly, but I couldn't reproduce this on my own devices. It probably had something to do with having extra initialization for Hive. Or initing Hive too late.

At least do not use this:

final appDocumentDir = await getApplicationDocumentsDirectory(); ..init(appDocumentDir.path)

I was able to move on by completely renaming my object so it would have a different stored name, it seems there is some sort of cache not being deleted, so I had to use a different object name, with a different hive box name with a different type id for each, and that worked.

hhajime commented 2 years ago

same error in 2022.

E/flutter ( 6595): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type '_OneByteString' is not a subtype of type 'int' in type cast
E/flutter ( 6595): #0      IngredientAdapter.read (package:grecipe/src/data/model/ingredient.g.dart:20)        
E/flutter ( 6595): #1      BinaryReaderImpl.read (package:hive/src/binary/binary_reader_impl.dart:328)
E/flutter ( 6595): #2      BinaryReaderImpl.readFrame (package:hive/src/binary/binary_reader_impl.dart:276)    
E/flutter ( 6595): #3      FrameHelper.framesFromBytes (package:hive/src/binary/frame_helper.dart:21)
E/flutter ( 6595): #4      FrameIoHelper.framesFromFile (package:hive/src/io/frame_io_helper.dart:42)
E/flutter ( 6595): <asynchronous suspension>
E/flutter ( 6595): #5      StorageBackendVm.initialize (package:hive/src/backend/vm/storage_backend_vm.dart:86)
E/flutter ( 6595): <asynchronous suspension>
E/flutter ( 6595): #6      HiveImpl._openBox (package:hive/src/hive_impl.dart:110)
E/flutter ( 6595): <asynchronous suspension>
E/flutter ( 6595): #7      HiveImpl.openBox (package:hive/src/hive_impl.dart:140)
E/flutter ( 6595): <asynchronous suspension>
E/flutter ( 6595): #8      main (package:grecipe/main.dart:19)
E/flutter ( 6595): <asynchronous suspension>

in my emulator it works, but it happens when I release on my real device .

solved. I changed my box name in main.dart await Hive.openBox('db'); -> await Hive.openBox('dbs');

but I cannot understand why hive db cache still in my phone after delete app. anyone answer please.

victorm97 commented 1 year ago

Try change android:allowBackup="false".

hhajime commented 1 year ago

Try change android:allowBackup="false".

Thanks. hope you have good day!