I try to make a simple app. App systems are like this: load json data → save inside db→display UI I use Isar db and Riverpod and want to realize it. However, I got an error when app launch at first. Error message is "flutter: type 'Null' is not a subtype of type 'User' in type cast" So I guess data is referenced before the data is stored. The process is asynchronous and well done, and I think I am handling it properly, but it doesn't seem to be working. I reload the app, the data is displayed. I also put Future.delay before return the build, I can get the display, but it isn't smart. Thank you for your cooperation.
isar_provider.dart
import 'package:asyncronize_sample/user.dart';
import 'package:isar/isar.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:path_provider/path_provider.dart';
part 'isar_provider.g.dart';
@Riverpod(keepAlive: true)
Future<Isar> isar(IsarRef ref) async {
final dir = await getApplicationDocumentsDirectory();
return Isar.open([UserSchema], directory: dir.path, inspector: true);
data2_provider.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:isar/isar.dart';
import 'package:asyncronize_sample/user.dart';
import 'package:asyncronize_sample/isar_provider.dart';
import 'package:flutter/services.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'data2_provider.g.dart';
@Riverpod(keepAlive: true)
class Data2 extends _$Data2 {
@override
FutureOr<User> build() async {
final isar = await ref.read(isarProvider.future);
final user = await isar.users.where().findFirst();
// if (user == null) {
// await save();
// print("Finish save");
// // await Future.delayed(Duration(seconds: 2));
// return await Future.value(await isar.users.where().findFirst());
// }
return Future.value(user);
}
Future<void> save() async {
// final json = await rootBundle.loadString('assets/data.json');
final json = await rootBundle.loadString('assets/data2.json').then((value) => jsonDecode(value) as Map<String, dynamic>);
final user = User()
..name = json['name']
..age = json['age'];
final isar = await ref.read(isarProvider.future);
isar.writeTxn(() async {
await isar.users.put(user);
print("Finish user writeTxn");
});
}
}
main.dart
class MainApp extends ConsumerWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
ref.read(data2Provider);
return const MaterialApp(
home: Scaffold(
body: HomeView2()
),
);
}
}
class HomeView2 extends ConsumerStatefulWidget {
const HomeView2({super.key});
@override
_HomeView2State createState() => _HomeView2State();
}
class _HomeView2State extends ConsumerState<HomeView2> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final user = ref.watch(data2Provider);
return Scaffold(
body: Center(
child: user.when(data: (userData) {
if (user.isLoading) {
return const CircularProgressIndicator();
}
if (user.isRefreshing) {
return const CircularProgressIndicator();
}
if (user.hasValue) {
setState(() {
debugPrint('user: ${userData.name}');
});
}
return Text(userData.name);
}
, error: (o, e){
debugPrint('Error: ${e.toString()}');
debugPrint(o.toString());
}, loading: (){
return const CircularProgressIndicator();
}),
),
);
}
}
You should load and override isar provider in main.dart.
isar_provider.dart
main.dart
Also, Don't use ref.read in build. (Check the MainApp Widget).