import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:whateatgo2/riverpod/myState.dart';
import 'package:whateatgo2/screen/home_screen.dart';
import 'model/recipe.dart';
void main() async {
await Hive.initFlutter();
Hive.registerAdapter(RecipeAdapter());
Box<Recipe> recipeBox = await Hive.openBox<Recipe>('recipeBox');
if (recipeBox.isEmpty) {
fetchData(); // JSON -> recipeBox 저장
}
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends ConsumerStatefulWidget {
const MyApp({super.key});
@override
ConsumerState<MyApp> createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
ref.read(shakeDetectorProvider.notifier).state.startListening();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// 앱의 라이프사이클 상태가 변경될 때마다 호출된다.
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.resumed:
ref.read(shakeDetectorProvider.notifier).state.startListening();
case AppLifecycleState.inactive:
break;
case AppLifecycleState.detached:
break;
case AppLifecycleState.hidden:
break;
case AppLifecycleState.paused:
ref.read(shakeDetectorProvider.notifier).state.stopListening();
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(), //ListScreen(),
theme: ThemeData(
fontFamily: 'SongMyung',
primaryColor: Colors.black,
//refresh 버튼 색깔
colorScheme: ColorScheme.fromSwatch().copyWith(
secondary: Colors.black,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
),
),
appBarTheme: const AppBarTheme(
color: Colors.transparent,
elevation: 0,
foregroundColor: Colors.black,
),
),
);
}
}
void fetchData() async {
//로컬 파일로부터 모든 레시피를 불러와 DB에 넣는다.
try {
//파일을 읽어와 List<Recipe>로 변환시킨다.
String jsonString = await rootBundle.loadString('sourceFile');
Map<String, dynamic> dataMap = jsonDecode(jsonString);
List<dynamic> dataList = dataMap['COOKRCP01']['row'];
List<Recipe> recipes =
dataList.map((json) => Recipe.fromJson(json)).toList();
//DB에 넣는다.
Box<Recipe> recipeBox = Hive.box('recipeBox');
recipeBox.addAll(recipes);
} catch (e) {
throw Exception(e);
}
}
import 'dart:math';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:shake/shake.dart';
import '../model/recipe.dart';
//1. 흔들었을때,refresh 버튼을 눌렀을때 random 인덱스값
final diceNumberProvider = StateNotifierProvider<DiceNumberNotifier, int>(
(ref) => DiceNumberNotifier(),
);
class DiceNumberNotifier extends StateNotifier<int> {
DiceNumberNotifier() : super(-1);
//주사위를 굴립니다.
void roll() {
state = Random().nextInt(1115); // 시작은 -1 , 0~1114
print(state);
}
}
//2. ShakeDetector Provider
final shakeDetectorProvider = StateProvider(
(ref) => ShakeDetector.waitForStart(
shakeThresholdGravity: 2,
onPhoneShake: () {
ref.read(diceNumberProvider.notifier).roll();
},
),
);
//3. 홈 화면에 후보군 리스트(초기값은 모든 리스트)
final homeScreenRecipesProvider = StateProvider((ref) =>
Hive.box('recipeBox').values.map((item) => Recipe.fromJson(item)).toList());
//4. 리스트 화면에 후보군 리스트(초기값은 모든 리스트)
//검색 필터를 적용한 리스트 Provider
//사용자가 화면상에서 떠나고 다시 진입했을 때 상태를 초기화 할 경우 autoDispose를 사용한다.
final listScreenRecipesProvider =
StateNotifierProvider.autoDispose<FilteredRecipeListNotifier, List<Recipe>>(
(ref) => FilteredRecipeListNotifier(),
);
class FilteredRecipeListNotifier extends StateNotifier<List<Recipe>> {
FilteredRecipeListNotifier()
: super(Hive.box('recipeBox')
.values
.map((item) => Recipe.fromJson(item))
.toList());
//필터할 대상(부모 리스트)
void setDefaultList() {
state = Hive.box('recipeBox')
.values
.map((item) => Recipe.fromJson(item))
.toList();
}
List<Recipe> normalFilterList(String keyword) {
//검색어를 포함하고있는 레시피 리스트
List<Recipe> filtered;
filtered = Hive.box('recipeBox')
.values
.map((item) => Recipe.fromJson(item))
.toList()
.where((element) =>
(element.rcpnm!.contains(keyword)) || //메뉴명
(element.rcppat2!.contains(keyword)) || //요리종류
(element.hashtag!.contains(keyword)) || //해쉬태그
(element.rcppartsdtls!.contains(keyword))) //재료정보
.toList();
state = filtered;
return filtered;
}
List<Recipe> filterInFilteredResult(String keyword) {
//검색어를 포함하고있는 레시피 리스트
List<Recipe> filtered;
filtered = state
.where((element) =>
(element.rcpnm!.contains(keyword)) || //메뉴명
(element.rcppat2!.contains(keyword)) || //요리종류
(element.hashtag!.contains(keyword)) || //해쉬태그
(element.rcppartsdtls!.contains(keyword))) //재료정보
.toList();
state = filtered;
return filtered;
}
}
This is my repository.
I read these: HiveError: The box "user" is already open and of type Box<User>
The box "name" is already open and of type Box<dynamic>
Flutter - HiveError: Box is Already Open
But, still I don't know how to fix my problem. Is it because of riverpod scope?
======== Exception caught by widgets library =======================================================
The following HiveError was thrown building HomeScreen(dirty, dependencies: [UncontrolledProviderScope], state: _ConsumerState#00fc9):
The box "recipebox" is already open and of type Box<Recipe>.
The relevant error-causing widget was:
HomeScreen HomeScreen:file:///C:/Users/kangs/StudioProjects/whateatgo/lib/main.dart:69:13
When the exception was thrown, this was the stack:
#1 _ExternalProviderSubscription.read (package:riverpod/src/framework/provider_base.dart:179:29)
#2 ConsumerStatefulElement.watch (package:flutter_riverpod/src/consumer.dart:571:8)
#3 HomeScreen.build (package:whateatgo2/screen/home_screen.dart:16:41)
#4 _ConsumerState.build (package:flutter_riverpod/src/consumer.dart:479:19)
#5 StatefulElement.build (package:flutter/src/widgets/framework.dart:5409:27)
#6 ConsumerStatefulElement.build (package:flutter_riverpod/src/consumer.dart:542:20)
#7 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5297:15)
#8 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5462:11)
#9 Element.rebuild (package:flutter/src/widgets/framework.dart:5016:7)
#10 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5279:5)
#11 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5453:11)
#12 ComponentElement.mount (package:flutter/src/widgets/framework.dart:5273:5)
... Normal element mounting (220 frames)
#232 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4182:16)
#233 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6569:36)
#234 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6581:32)
... Normal element mounting (449 frames)
#683 _UncontrolledProviderScopeElement.mount (package:flutter_riverpod/src/framework.dart:309:11)
... Normal element mounting (35 frames)
#718 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4182:16)
#719 Element.updateChild (package:flutter/src/widgets/framework.dart:3707:18)
#720 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1253:16)
#721 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1222:5)
#722 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1169:18)
#723 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2719:19)
#724 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1168:13)
#725 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:1001:7)
#726 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:981:7)
#730 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:189:12)
#731 HiveImpl._getBoxInternal (package:hive/src/hive_impl.dart:182:9)
#732 HiveImpl.box (package:hive/src/hive_impl.dart:197:33)
#733 homeScreenRecipesProvider.<anonymous closure> (package:whateatgo2/riverpod/myState.dart:36:10)
#734 ProviderContainer.listen (package:riverpod/src/framework/container.dart:285:21)
#735 ConsumerStatefulElement.watch.<anonymous closure> (package:flutter_riverpod/src/consumer.dart:567:25)
#736 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:535:23)
#737 ConsumerStatefulElement.watch (package:flutter_riverpod/src/consumer.dart:560:26)
#738 HomeScreen.build (package:whateatgo2/screen/home_screen.dart:16:41)
#739 _ConsumerState.build (package:flutter_riverpod/src/consumer.dart:479:19)
#740 StatefulElement.build (package:flutter/src/widgets/framework.dart:5409:27)
#741 ConsumerStatefulElement.build (package:flutter_riverpod/src/consumer.dart:542:20)
#742 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5297:15)
#743 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5462:11)
#744 Element.rebuild (package:flutter/src/widgets/framework.dart:5016:7)
#745 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5279:5)
#746 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5453:11)
#747 ComponentElement.mount (package:flutter/src/widgets/framework.dart:5273:5)
... Normal element mounting (220 frames)
#967 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4182:16)
#968 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6569:36)
#969 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6581:32)
... Normal element mounting (449 frames)
#1418 _UncontrolledProviderScopeElement.mount (package:flutter_riverpod/src/framework.dart:309:11)
... Normal element mounting (35 frames)
#1453 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4182:16)
#1454 Element.updateChild (package:flutter/src/widgets/framework.dart:3707:18)
#1455 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1253:16)
#1456 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1222:5)
#1457 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1169:18)
#1458 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2719:19)
#1459 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1168:13)
#1460 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:1001:7)
#1461 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:981:7)
#1465 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:189:12)
(elided 6 frames from class _Timer and dart:async-patch)
Reading Hive.box('recipeBox').values
gives you Iterable<Recipe>
, so you don't need to map it from JSON.
//필터할 대상(부모 리스트)
void setDefaultList() {
state = Hive.box('recipeBox')
.values
// .map((item) => Recipe.fromJson(item)) <-- remove this line
.toList();
}
You can notice the error if you add the type when calling .box
like this: Hive.box<Recipe>('recipeBox')
. Do this to every call on .box
in your code.