Question
When the new object is created and added into the flashcardsBox it saves all the fields except frontImages and backImages lists. But when I restart the app these fields look like being saved. How to fix that such that all the object's fields will be added to a box immediately after flashcardsBox.add(flashcard) was called?

after next run:

Code sample
Flashcard model:
import 'package:hive/hive.dart';
import 'package:my_flashcards/models/deck.dart';
part 'flashcard.g.dart';
@HiveType(typeId: 1)
class Flashcard {
@HiveField(0)
final String frontText;
@HiveField(1)
List<String> frontImages;
@HiveField(2)
final String backText;
@HiveField(3)
List<String> backImages;
@HiveField(4)
final Deck deck;
@HiveField(5)
final int numberOfRepetitions;
@HiveField(6)
final double eFactor;
@HiveField(7)
final int quality;
@HiveField(8)
final int interval;
@HiveField(9)
final DateTime nextReviewDate;
Flashcard(
{this.frontText,
this.frontImages,
this.backText,
this.backImages,
this.deck,
this.numberOfRepetitions,
this.eFactor,
this.quality,
this.interval,
this.nextReviewDate});
}
How it is saved:
final flashcard = Flashcard(
frontText: frontFormTextEditingController.text,
frontImages: frontImagesPaths,
backText: backFormTextEditingController.text,
backImages: backImagesPaths,
deck: selectedDeckBox.getAt(0),
numberOfRepetitions: 0,
eFactor: 2.5,
quality: 4,
nextReviewDate: DateTime.now(),
interval: 0);
flashcardsBox.add(flashcard);
_where frontImagesPaths and backImagesPaths are Lists of String_
How it is showed:
class FlashcardsList extends StatefulWidget {
@override
_FlashcardsListState createState() => _FlashcardsListState();
}
class _FlashcardsListState extends State<FlashcardsList> {
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: flashcardsBox.listenable(),
builder: (BuildContext context, Box<Flashcard> box, Widget child) {
List<Flashcard> flashcards = box.values.toList();
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => FlashcardSmall(
flashcard: flashcards[flashcards.length - index - 1]),
childCount: flashcards.length,
),
);
},
);
}
}
Version
I need to test this, thanks for letting me know.
I need to test this, thanks for letting me know.
I've tested the issue and probably there are no problems with Hive in this case, every list of strings was correctly added to the model and was shown immediately after adding to box.
So problem may be with the way I'm picking an Image from gallery and adding the list of images paths to model's field. I wrote the simplest code to show the issue. And the result is:
_After adding to box:_

_After rerun_

So that's the code:
pubspec.yaml
name: issue
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
hive: ^1.4.0+1
hive_flutter: ^0.3.0+1
image_picker: ^0.6.3+1
dev_dependencies:
hive_generator: ^0.7.0
build_runner: ^1.7.4
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
main.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:issue/view.dart';
import 'model.dart';
void main() async {
await initHive();
runApp(View());
}
Future<void> initHive() async {
await Hive.initFlutter();
Hive.registerAdapter<Model>(ModelAdapter());
await Hive.openBox<Model>('modelsBox');
}
model.dart
import 'package:hive/hive.dart';
part 'model.g.dart';
@HiveType(typeId: 0)
class Model {
@HiveField(0)
final List<String> items;
Model({this.items});
}
// flutter packages pub run build_runner watch --delete-conflicting-outputs
pick_image.dart
import 'dart:async';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
class ImagesComponent {
Directory appDocumentsDir;
String savingPath;
ImagesComponent() {
init();
}
void init() async {
appDocumentsDir = await getApplicationDocumentsDirectory();
// getting a directory path for saving
savingPath = appDocumentsDir.absolute.path;
}
Future<String> pickImageAndGetPath(ImageSource source) async {
File imageFile =
await ImagePicker.pickImage(source: source, imageQuality: 100);
// Handling Main Activity destruction on Android
if (imageFile == null) {
print('retrieving lost data');
imageFile = await retrieveLostData();
}
return imageFile.path;
}
// Handling MainActivity destruction on Android
Future<File> retrieveLostData() async {
final LostDataResponse response = await ImagePicker.retrieveLostData();
return response.file;
}
}
view.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:issue/pick_image.dart';
import 'model.dart';
class View extends StatefulWidget {
@override
_ViewState createState() => _ViewState();
}
class _ViewState extends State<View> {
var imagesComponent = ImagesComponent();
List<String> imagePaths = [];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Issue example'),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () async {
// pick image from gallery
String imagePath =
await imagesComponent.pickImageAndGetPath(ImageSource.gallery);
// fill the list three times with selected image's path
for (int i = 0; i < 3; i++) {
imagePaths.add(imagePath);
}
await Hive.box<Model>('modelsBox').add(Model(items: imagePaths));
imagePaths.clear();
},
),
body: ValueListenableBuilder(
valueListenable: Hive.box<Model>('modelsBox').listenable(),
builder: (BuildContext context, Box box, Widget child) {
var models = box.values.toList().reversed.toList();
return ListView.builder(
itemCount: models.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
'${models.length - index} ${models[index].items.toString()}'));
},
);
},
),
),
);
}
}
Where could the problem be? @leisim
Here is the problem:
await Hive.box<Model>('modelsBox').add(Model(items: imagePaths));
imagePaths.clear()
When you add (or put) an object to Hive, it will not be copied but used as-is. That means if you alter the object instance from somewhere, you also change the object that Hive has in memory. This does not affect the persisted data.
You clear the imagePaths list so the Model instance you added to Hive also has an empty list. When you restart the app, a new, filled list is loaded from the disk.
Replace the code above with this and it should work:
await Hive.box<Model>('modelsBox').add(Model(items: imagePaths.toList()));
imagePaths.clear()
Now each Model instance has its own list instance.
Here is the problem:
await Hive.box<Model>('modelsBox').add(Model(items: imagePaths)); imagePaths.clear()When you add (or put) an object to Hive, it will not be copied but used as-is. That means if you alter the object instance from somewhere, you also change the object that Hive has in memory. This does not affect the persisted data.
You clear the
imagePathslist so theModelinstance you added to Hive also has an empty list. When you restart the app, a new, filled list is loaded from the disk.
Replace the code above with this and it should work:await Hive.box<Model>('modelsBox').add(Model(items: imagePaths.toList())); imagePaths.clear()Now each
Modelinstance has its own list instance.
Thanks a lot. It works now.