Edit: solved by adding a unique key
to the widget constructor
call:
Edit 2: as Randal Schwartz mentioned -> this is not a solution. Issue NOT solved and still open.
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
key: UniqueKey(),
currentSearchTermInputContent:
widgetRef.read(apiEndpointUniversalSearchTermInputContentProvider),
captionList: ["Statement"],
// todo : allow umlauts! or better deny numbers?
inputFormatterAllow: RegExp(".*"),
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
I have an abstract class
(ApiEndpoint) with two implementation
s (ApiEndpointName, ApiEndpointUniversal).
Both implementation
s have a StatefulWidget
(SearchTermInputOneString) inherit
ed from the same base class
(SearchTermInput).
For both ApiEndpoint-objects the Widget part of SearchTermInputOneStringis created separately - what is correct. My problem is, that the State-part of SearchTermInputOneString is created only once - so ApiEndpointName and ApiEndpointUniversal own the same state.
I have to read ApiEndpoint-specific configuration during initState
- that does not work because initState
is called only for the first ApiEndpoint-instance :(
Any ideas how to solve that?
abstract class
ApiEndpoint:
enum ApiEndpointType {
today,
unseen,
universal,
name,
exactAge,
ageBetween,
ageGreaterThanOrEqual,
ageLessThanOrEqual
}
abstract class ApiEndpoint {
ApiEndpointType get type;
String get title;
SearchTermInput get searchTermInput;
String get searchFunctionName;
bool validateData(BuildContext context, WidgetRef ref);
void onSubmit(
BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
void onLostFocus(
BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
}
ApiEndpointName implementation:
class ApiEndpointName implements ApiEndpoint {
final WidgetRef widgetRef;
ApiEndpointName({required this.widgetRef});
@override
String get searchFunctionName => "getObituariesByName";
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
currentSearchTermInputContent:
widgetRef.read(apiEndpointNameSearchTermInputContentProvider),
captionList: ["Name"],
inputFormatterAllow: RegExp("[a-zA-Z% ]"),
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
@override
String get title => "... by name";
@override
ApiEndpointType get type => ApiEndpointType.name;
@override
bool validateData(BuildContext context, WidgetRef ref) {
...
}
@override
void onSubmit(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
@override
void onLostFocus(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
ApiEndpointUniversal implementation:
class ApiEndpointUniversal implements ApiEndpoint {
final WidgetRef widgetRef;
ApiEndpointUniversal({required this.widgetRef});
@override
String get searchFunctionName => "getObituariesUniversal";
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
currentSearchTermInputContent:
widgetRef.read(apiEndpointUniversalSearchTermInputContentProvider),
captionList: ["Statement"],
inputFormatterAllow: RegExp(".*"),
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
@override
String get title => "... universal";
@override
ApiEndpointType get type => ApiEndpointType.universal;
@override
bool validateData(BuildContext context, WidgetRef ref) {
...
}
@override
void onSubmit(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
@override
void onLostFocus(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
}
abstract
StatefulWidget:
abstract class SearchTermInput extends ConsumerStatefulWidget {
const SearchTermInput({super.key});
List<String> get currentSearchTermInputContent;
List<String>? get captionList;
RegExp get inputFormatterAllow;
void Function(BuildContext, WidgetRef, List<String>) get onSubmit;
void Function(BuildContext, WidgetRef, List<String>) get onLostFocus;
}
Implementation:
class SearchTermInputOneString extends SearchTermInput {
@override
final List<String> currentSearchTermInputContent;
@override
final List<String> captionList;
@override
final RegExp inputFormatterAllow;
@override
final void Function(BuildContext, WidgetRef, List<String>) onSubmit;
@override
final void Function(BuildContext, WidgetRef, List<String>) onLostFocus;
const SearchTermInputOneString({
super.key,
required this.currentSearchTermInputContent,
required this.captionList,
required this.inputFormatterAllow,
required this.onSubmit,
required this.onLostFocus,
});
@override
ConsumerState<ConsumerStatefulWidget> createState() =>
_SearchTermInputOneStringState();
}
class _SearchTermInputOneStringState
extends ConsumerState<SearchTermInputOneString> {
late TextEditingController textEditingController;
@override
void initState() {
super.initState();
textEditingController = TextEditingController();
textEditingController.text = widget.currentSearchTermInputContent.isNotEmpty
? widget.currentSearchTermInputContent[0]
: "";
}
@override
void dispose() {
textEditingController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Focus(
child: TextFormField(
controller: textEditingController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: widget.captionList.isNotEmpty ? widget.captionList[0] : "",
suffixIcon: IconButton(
onPressed: () {
textEditingController.text = "";
},
icon: Icon(Icons.clear),
),
),
inputFormatters: [
FilteringTextInputFormatter.allow(widget.inputFormatterAllow)
],
onFieldSubmitted: (_) {
widget.onSubmit(context, ref, [textEditingController.text]);
},
),
onFocusChange: (hasFocus) {
if (!hasFocus) {
widget.onLostFocus(context, ref, [textEditingController.text]);
}
},
);
}
}
I create the List of ApiEndpoints this way:
List<ApiEndpoint> getApiEndPoints({required WidgetRef widgetRef}) {
final List<ApiEndpoint> apiEndpoints = [
ApiEndpointName(widgetRef: widgetRef),
ApiEndpointUniversal(widgetRef: widgetRef),
];
return apiEndpoints;
}
Edit: solved by adding a unique key
to the widget constructor
call:
Edit 2: as Randal Schwartz mentioned -> this is not a solution. Issue NOT solved and still open.
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
key: UniqueKey(),
currentSearchTermInputContent:
widgetRef.read(apiEndpointUniversalSearchTermInputContentProvider),
captionList: ["Statement"],
// todo : allow umlauts! or better deny numbers?
inputFormatterAllow: RegExp(".*"),
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
I have an abstract class
(ApiEndpoint) with two implementation
s (ApiEndpointName, ApiEndpointUniversal).
Both implementation
s have a StatefulWidget
(SearchTermInputOneString) inherit
ed from the same base class
(SearchTermInput).
For both ApiEndpoint-objects the Widget part of SearchTermInputOneStringis created separately - what is correct. My problem is, that the State-part of SearchTermInputOneString is created only once - so ApiEndpointName and ApiEndpointUniversal own the same state.
I have to read ApiEndpoint-specific configuration during initState
- that does not work because initState
is called only for the first ApiEndpoint-instance :(
Any ideas how to solve that?
abstract class
ApiEndpoint:
enum ApiEndpointType {
today,
unseen,
universal,
name,
exactAge,
ageBetween,
ageGreaterThanOrEqual,
ageLessThanOrEqual
}
abstract class ApiEndpoint {
ApiEndpointType get type;
String get title;
SearchTermInput get searchTermInput;
String get searchFunctionName;
bool validateData(BuildContext context, WidgetRef ref);
void onSubmit(
BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
void onLostFocus(
BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
}
ApiEndpointName implementation:
class ApiEndpointName implements ApiEndpoint {
final WidgetRef widgetRef;
ApiEndpointName({required this.widgetRef});
@override
String get searchFunctionName => "getObituariesByName";
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
currentSearchTermInputContent:
widgetRef.read(apiEndpointNameSearchTermInputContentProvider),
captionList: ["Name"],
inputFormatterAllow: RegExp("[a-zA-Z% ]"),
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
@override
String get title => "... by name";
@override
ApiEndpointType get type => ApiEndpointType.name;
@override
bool validateData(BuildContext context, WidgetRef ref) {
...
}
@override
void onSubmit(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
@override
void onLostFocus(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
ApiEndpointUniversal implementation:
class ApiEndpointUniversal implements ApiEndpoint {
final WidgetRef widgetRef;
ApiEndpointUniversal({required this.widgetRef});
@override
String get searchFunctionName => "getObituariesUniversal";
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
currentSearchTermInputContent:
widgetRef.read(apiEndpointUniversalSearchTermInputContentProvider),
captionList: ["Statement"],
inputFormatterAllow: RegExp(".*"),
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
@override
String get title => "... universal";
@override
ApiEndpointType get type => ApiEndpointType.universal;
@override
bool validateData(BuildContext context, WidgetRef ref) {
...
}
@override
void onSubmit(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
@override
void onLostFocus(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
...
}
}
abstract
StatefulWidget:
abstract class SearchTermInput extends ConsumerStatefulWidget {
const SearchTermInput({super.key});
List<String> get currentSearchTermInputContent;
List<String>? get captionList;
RegExp get inputFormatterAllow;
void Function(BuildContext, WidgetRef, List<String>) get onSubmit;
void Function(BuildContext, WidgetRef, List<String>) get onLostFocus;
}
Implementation:
class SearchTermInputOneString extends SearchTermInput {
@override
final List<String> currentSearchTermInputContent;
@override
final List<String> captionList;
@override
final RegExp inputFormatterAllow;
@override
final void Function(BuildContext, WidgetRef, List<String>) onSubmit;
@override
final void Function(BuildContext, WidgetRef, List<String>) onLostFocus;
const SearchTermInputOneString({
super.key,
required this.currentSearchTermInputContent,
required this.captionList,
required this.inputFormatterAllow,
required this.onSubmit,
required this.onLostFocus,
});
@override
ConsumerState<ConsumerStatefulWidget> createState() =>
_SearchTermInputOneStringState();
}
class _SearchTermInputOneStringState
extends ConsumerState<SearchTermInputOneString> {
late TextEditingController textEditingController;
@override
void initState() {
super.initState();
textEditingController = TextEditingController();
textEditingController.text = widget.currentSearchTermInputContent.isNotEmpty
? widget.currentSearchTermInputContent[0]
: "";
}
@override
void dispose() {
textEditingController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Focus(
child: TextFormField(
controller: textEditingController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: widget.captionList.isNotEmpty ? widget.captionList[0] : "",
suffixIcon: IconButton(
onPressed: () {
textEditingController.text = "";
},
icon: Icon(Icons.clear),
),
),
inputFormatters: [
FilteringTextInputFormatter.allow(widget.inputFormatterAllow)
],
onFieldSubmitted: (_) {
widget.onSubmit(context, ref, [textEditingController.text]);
},
),
onFocusChange: (hasFocus) {
if (!hasFocus) {
widget.onLostFocus(context, ref, [textEditingController.text]);
}
},
);
}
}
I create the List of ApiEndpoints this way:
List<ApiEndpoint> getApiEndPoints({required WidgetRef widgetRef}) {
final List<ApiEndpoint> apiEndpoints = [
ApiEndpointName(widgetRef: widgetRef),
ApiEndpointUniversal(widgetRef: widgetRef),
];
return apiEndpoints;
}
Share
Improve this question
edited Nov 18, 2024 at 7:46
user28298940
asked Nov 16, 2024 at 14:22
user28298940user28298940
112 bronze badges
3
- "key: UniqueKey(),"... WTF. bye bye performance. It's keeping your widget alive by design. and you've just ruined that. You've hooked into the wrong State lifecycle. You probably want api.flutter.dev/flutter/widgets/State/… and not initState. – Randal Schwartz Commented Nov 16, 2024 at 21:58
- I do not understand :( Everywhere I read "Do your initialization in initState" - what is wrong now? The initialization of the TextController? Or the Key? I read that a WidgetObject gets its own StateObject when I define a unique key for each StatelessWidget. When I do not set the key, neither initState is called nor createState in the WidgetObject - therefore didChangeDependencie would not be called, too - did it? – user28298940 Commented Nov 18, 2024 at 5:36
- Okay - after thinking about your words a bit longer I suppose to understand what you mean. The widget (also it's state!) should live for the whole lifetime of the app (in best case) and only the state dependencies should be updated if needed. But with setting the unique keys I force destroying and recreating the widget - makes sense. But unfortunately I am not able to get this didChangeDependencies being called when I switch from the "Search by name" to the "Universal search" widget. Please have a look at my code below. – user28298940 Commented Nov 18, 2024 at 8:35
2 Answers
Reset to default 1After playing around a lot of time without getting didChangeDependencies
to work I found out that didUpdateWidget
did the trick. Do you think that this okay or is there another stumbling block that I overlooked?
@override
void didUpdateWidget(covariant SearchTermInputOneString oldWidget) {
final log = getLogger();
log.t("didUpdateWidget");
// read apiEndpoint content
currentContent = ref
.read(widget.apiEndpointSearchTermInputContentProvider)
.cast<String>();
textEditingController.text =
currentContent.isNotEmpty ? currentContent[0] : "";
super.didUpdateWidget(oldWidget);
}
Okay, I changed my code but unfortunately I now got the same problem - the state is not updated for the second Widget-Instance (only if the first instance is disposed before!) :(
This is how the code now looks:
Widget that changes the widgets (for "Search via Name" and "Universal Search"):
@override
Widget build(BuildContext context) {
_runsAfterBuild(context, ref);
final currentApiEndpoint = ref.watch(currentApiEndpointProvider);
return Scaffold(
appBar: AppBar(
title: const Text("Search obituaries ..."),
centerTitle: true,
actions: [
IconButton(
tooltip: "Start search...",
onPressed: () {
doSearch(context, ref);
},
icon: const Icon(Icons.search)),
],
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
DropdownButtonFormField<ApiEndpoint>(
items: dropDownMenuItems,
value: currentApiEndpoint,
onChanged: (apiEndpoint) {
doOnDropDownChanged(context, ref, apiEndpoint);
}),
const SizedBox(
height: 10,
),
currentApiEndpoint.searchTermInput,
],
),
),
),
);
}
BaseClass for the ApiEndpoint implementations:
abstract class ApiEndpoint {
ApiEndpointType get type;
String get title;
SearchTermInput get searchTermInput;
String get searchFunctionName;
bool validateData(BuildContext context, WidgetRef ref);
void onSubmit(
BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
void onLostFocus(
BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
}
ApiEndpoint-Class that owns the widget for the first instance of the widget (Search via name):
class ApiEndpointName implements ApiEndpoint {
final log = getLogger();
final NotifierProvider<ApiEndpointNameSearchTermInputContent, List<String>>
apiEndpointSearchTermInputContentProvider =
apiEndpointNameSearchTermInputContentProvider;
ApiEndpointName();
@override
String get searchFunctionName => "getObituariesByName";
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
// key: Key("ApiEndpointName"), // UniqueKey(),
apiEndpointSearchTermInputContentProvider:
apiEndpointSearchTermInputContentProvider,
captionList: ["Name"],
textInputFormatter: [
FilteringTextInputFormatter.deny(RegExp(r"[0-9]"))
],
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
@override
String get title => "... by name";
@override
ApiEndpointType get type => ApiEndpointType.name;
@override
bool validateData(BuildContext context, WidgetRef ref) {
var contentList = ref.read(apiEndpointSearchTermInputContentProvider);
return contentList.isNotEmpty && contentList[0].isNotEmpty;
}
@override
void onSubmit(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
// set values
ref
.read(currentSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
ref
.read(apiEndpointSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
// start search
var doSearch = ref.read(doSearchFunctionProvider);
if (doSearch != null) {
doSearch(context, ref);
} else {
log.d("no doSearch method found!");
}
}
@override
void onLostFocus(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
// set values
ref
.read(currentSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
ref
.read(apiEndpointSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
}
}
ApiEndpoint-Class that owns the widget for the second instance of the widget (Universal search):
class ApiEndpointUniversal implements ApiEndpoint {
final log = getLogger();
final NotifierProvider<ApiEndpointUniversalSearchTermInputContent,
List<String>> apiEndpointSearchTermInputContentProvider =
apiEndpointUniversalSearchTermInputContentProvider;
ApiEndpointUniversal();
@override
String get searchFunctionName => "getObituariesUniversal";
@override
SearchTermInput get searchTermInput => SearchTermInputOneString(
// key: Key("ApiEndpointUniversal"), // UniqueKey(),
apiEndpointSearchTermInputContentProvider:
apiEndpointSearchTermInputContentProvider,
captionList: ["Statement"],
textInputFormatter: [FilteringTextInputFormatter.allow(RegExp(r".*"))],
onSubmit: onSubmit,
onLostFocus: onLostFocus,
);
@override
String get title => "... universal";
@override
ApiEndpointType get type => ApiEndpointType.universal;
@override
bool validateData(BuildContext context, WidgetRef ref) {
var contentList = ref.read(apiEndpointSearchTermInputContentProvider);
return contentList.isNotEmpty && contentList[0].isNotEmpty;
}
@override
void onSubmit(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
// set values
ref
.read(currentSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
ref
.read(apiEndpointSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
// start search
var doSearch = ref.read(doSearchFunctionProvider);
if (doSearch != null) {
doSearch(context, ref);
} else {
log.d("no doSearch method found!");
}
}
@override
void onLostFocus(BuildContext context, WidgetRef ref,
List<String> searchTermInputContent) {
// set values
ref
.read(currentSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
ref
.read(apiEndpointSearchTermInputContentProvider.notifier)
.setValue(searchTermInputContent);
}
}
BaseClass of the Widget:
abstract class SearchTermInput extends ConsumerStatefulWidget {
const SearchTermInput({super.key});
NotifierProvider? get apiEndpointSearchTermInputContentProvider;
List<String>? get captionList;
List<TextInputFormatter>? get textInputFormatter;
void Function(BuildContext, WidgetRef, List<String>) get onSubmit;
void Function(BuildContext, WidgetRef, List<String>) get onLostFocus;
}
Widget implementation for ApiEndpointName and ApiEndpointUniversal:
class SearchTermInputOneString extends SearchTermInput {
@override
final NotifierProvider apiEndpointSearchTermInputContentProvider;
@override
final List<String> captionList;
@override
final List<TextInputFormatter>? textInputFormatter;
@override
final void Function(BuildContext, WidgetRef, List<String>) onSubmit;
@override
final void Function(BuildContext, WidgetRef, List<String>) onLostFocus;
const SearchTermInputOneString({
super.key,
required this.apiEndpointSearchTermInputContentProvider,
required this.captionList,
required this.textInputFormatter,
required this.onSubmit,
required this.onLostFocus,
});
@override
// ignore: no_logic_in_create_state - this is temporarily for for logging!
ConsumerState<ConsumerStatefulWidget> createState() {
final log = getLogger();
log.t("createState");
return _SearchTermInputOneStringState();
}
}
class _SearchTermInputOneStringState
extends ConsumerState<SearchTermInputOneString> {
late TextEditingController textEditingController;
late List<String> currentContent;
@override
void initState() {
super.initState();
final log = getLogger();
log.t("initstate");
textEditingController = TextEditingController();
}
@override
void didChangeDependencies() {
_runsAfterInit(context, ref);
final log = getLogger();
log.t("didChangeDependencies");
// read apiEndpoint content
currentContent = ref
.read(widget.apiEndpointSearchTermInputContentProvider)
.cast<String>();
textEditingController.text =
currentContent.isNotEmpty ? currentContent[0] : "";
super.didChangeDependencies();
}
@override
void dispose() {
textEditingController.dispose();
final log = getLogger();
log.t("dispose");
super.dispose();
}
Future<void> _runsAfterInit(BuildContext context, WidgetRef ref) async {
await Future.delayed(Duration.zero); // <-- Add a 0 dummy waiting time
final log = getLogger();
log.t("_runsAfterInit");
// set current content
ref
.read(currentSearchTermInputContentProvider.notifier)
.setValue(currentContent);
}
@override
Widget build(BuildContext context) {
return Focus(
child: TextFormField(
controller: textEditingController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: widget.captionList.isNotEmpty ? widget.captionList[0] : "",
suffixIcon: IconButton(
onPressed: () {
textEditingController.text = "";
},
icon: Icon(Icons.clear),
),
),
inputFormatters: widget.textInputFormatter,
onFieldSubmitted: (_) {
widget.onSubmit(context, ref, [textEditingController.text]);
},
),
onFocusChange: (hasFocus) {
if (!hasFocus) {
widget.onLostFocus(context, ref, [textEditingController.text]);
}
},
);
}
}
Logoutput after the first instance has been created:
────────────────────────────────────────────────────────────────────────────────────────
#0 SearchTermInputOneString.createState (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:39:9)
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-11-18 08:26:03.262
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
createState
────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────────────
#0 _SearchTermInputOneStringState.initState (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:53:9)
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-11-18 08:26:03.269
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
initstate
────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────────────
#0 _SearchTermInputOneStringState.didChangeDependencies (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:61:9)
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-11-18 08:26:03.272
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
didChangeDependencies
────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────────────
#0 ApiEndpointNameSearchTermInputContent.build (package:obituary_viewer/features/obituaries/presentation/provider/search_term_input_content_provider.dart:26:9)
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-11-18 08:26:03.275
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
ApiEndpointNameSearchTermInputContent provider build
────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────────────
#0 DoSearchFunction.build (package:obituary_viewer/features/obituaries/presentation/provider/search_screen_provider.dart:13:9)
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-11-18 08:26:03.402
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
DoSearchFunction provider build
────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────────────
#0 DoSearchFunction.setValue (package:obituary_viewer/features/obituaries/presentation/provider/search_screen_provider.dart:19:9)
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-11-18 08:26:03.404
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
DoSearchFunction set to Closure: (BuildContext, WidgetRef) => void from Function 'doSearch':.
────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────────────
#0 _SearchTermInputOneStringState._runsAfterInit (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:85:9)
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-11-18 08:26:03.405
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
_runsAfterInit
────────────────────────────────────────────────────────────────────────────────────────
Logoutput after the second instance:
> flutter:
> ┌─────────────────────────────────────────────────────────────────────────────────────────
> flutter: │ #0 CurrentApiEndpoint.setValue
> (package:obituary_viewer/features/obituaries/presentation/provider/api_endpoint_provider.dart:30:9)
> flutter:
> ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
> flutter: │ 2024-11-18 08:27:41.773 flutter:
> ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
> flutter: │ CurrentApiEndpoints set to Instance of
> 'ApiEndpointUniversal' flutter:
> └─────────────────────────────────────────────────────────────────────────────────────────
That's it - no create
, no initState
(what seems to be correct after deleting the unique key), no didChangeDependencies
:( - and the text of the texteditingcontroller is still the one of the first instance :(
I am at the very beginning of my “flutter career” and don't want to learn anything wrong. I am therefore very grateful for your advice!
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745656911a4638597.html
评论列表(0条)