-
-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
removeOverlay condition too strict #182
Comments
Hello @franzlst, Thanks for the detailed issue. I will take a look at it soon currently afk. |
Hi @franzlst, Are you seeing this issue on the latest flutter stable channel? Unfortunately I am unable to reproduce it code sample// import 'package:example/pagination.dart';
import 'package:flutter/material.dart';
import 'package:searchfield/searchfield.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
themeMode: ThemeMode.light,
theme: ThemeData(
colorSchemeSeed: Colors.indigo,
useMaterial3: true,
brightness: Brightness.light,
),
darkTheme: ThemeData(
colorSchemeSeed: Colors.blue,
useMaterial3: true,
brightness: Brightness.dark,
),
home: SearchFieldSample(),
debugShowCheckedModeBanner: false,
);
}
}
class SearchFieldSample extends StatefulWidget {
const SearchFieldSample({Key? key}) : super(key: key);
@override
State<SearchFieldSample> createState() => _SearchFieldSampleState();
}
class _SearchFieldSampleState extends State<SearchFieldSample> {
@override
void initState() {
suggestions = [
'United States',
'Germany',
'Canada',
'United Kingdom',
'France',
'Italy',
'Spain',
'Australia',
'India',
'China',
'Japan',
'Brazil',
'South Africa',
'Mexico',
'Argentina',
'Russia',
'Indonesia',
'Turkey',
'Saudi Arabia',
'Nigeria',
'Egypt',
];
selected = suggestions[0];
super.initState();
}
int suggestionsCount = 12;
var suggestions = <String>[];
var selected = '';
@override
Widget build(BuildContext context) {
Widget searchChild(x, {bool isSelected = false}) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(x,
style: TextStyle(
fontSize: 18,
color: isSelected ? Colors.green : Colors.black)),
);
return Scaffold(
appBar: AppBar(title: Text('Searchfield Demo')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SearchField<String>(
maxSuggestionsInViewPort: 10,
suggestionAction: SuggestionAction.unfocus,
searchInputDecoration: SearchInputDecoration(
hintText: 'Search',
cursorColor: Colors.blue,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
onSuggestionTap: (SearchFieldListItem<String> item) {
setState(() {
selected = item.searchKey;
});
},
suggestions: suggestions
.map(
(e) => SearchFieldListItem<String>(e,
item: e,
child: searchChild(e, isSelected: e == selected)),
)
.toList(),
),
),
],
),
));
}
}
output_video.mov |
@maheshj01 Thank you for looking into this. The following is a minimum example with which I can reproduce the issue: import 'package:flutter/material.dart';
import 'package:searchfield/searchfield.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Searchfield Crash',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Searchfield Crash'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SearchField<String>(
suggestionAction: SuggestionAction.unfocus,
suggestions: const [],
initialValue: null, // user actively ne
textInputAction: TextInputAction.search,
suggestionState: Suggestion.hidden,
emptyWidget: const SizedBox.shrink(),
suggestionDirection: SuggestionDirection.flex,
),
],
),
),
);
}
} In order to reproduce it, you need to build it ( I always get the following exceptions:
I tried to generate source maps, but somehow this doesn't work. In any case, when changing the code as described above, the issue no longer occurs. |
Some additional info: I was now able to use source maps to pin point the source of the exception: At some point Within |
Thanks for the details @franzlst, Unfortunately I am not able to reproduce that issue on my end, I understand the mounted condition is not required, Also, removing |
@maheshj01 That's a pity. Do you think it's an option to re-create the Overlay every time it's being required instead of re-using it? So basically calling |
I think that would be unnecessary work to recreate the overlay everytime, considering the overlay widget could be a custom heavy widget with long list of items, But we can compromise performance (only in worst case scenarios) as a work around to prevent the exception that you are receiving until this is resolved flutter/flutter#145466 Does recreating overlay fixes issue on your end? If so, I can go ahead and submit a new release |
@maheshj01 I think a found a good compromise: Widget? _streamBuilder;
OverlayEntry _createOverlay() {
return OverlayEntry(builder: (context) {
if(_streamBuilder != null) return _streamBuilder!;
final textFieldRenderBox =
key.currentContext!.findRenderObject() as RenderBox;
final textFieldsize = textFieldRenderBox.size;
final offset = textFieldRenderBox.localToGlobal(Offset.zero);
var yOffset = Offset.zero;
_totalHeight = widget.maxSuggestionsInViewPort * widget.itemHeight;
_streamBuilder = StreamBuilder<List<SearchFieldListItem?>?>(
stream: suggestionStream.stream,
builder: (BuildContext context,
AsyncSnapshot<List<SearchFieldListItem?>?> snapshot) {
late var count = widget.maxSuggestionsInViewPort;
if (snapshot.data != null) {
count = snapshot.data!.length;
}
yOffset = getYOffset(offset, textFieldsize, count) ?? Offset.zero;
return Positioned(
left: offset.dx,
width: widget.suggestionsDecoration?.width ?? textFieldsize.width,
child: CompositedTransformFollower(
offset: widget.offset ?? yOffset,
link: _layerLink,
child: Material(
borderRadius: widget.suggestionsDecoration?.borderRadius ??
BorderRadius.zero,
shadowColor: widget.suggestionsDecoration?.shadowColor,
elevation: widget.suggestionsDecoration?.elevation ??
kDefaultElevation,
child: _suggestionsBuilder(),
),
),
);
});
return _streamBuilder!;
});
} What I tried this changing void removeOverlay() {
final overlay = _overlayEntry;
_overlayEntry = null;
if (overlay != null && overlay!.mounted) {
isSuggestionsShown = false;
overlay!.remove();
}
}
} And always creating the With those changes (that probably hardly have an influence on performance), I am no longer able to reproduce the issue. |
Edit: Nevermind submitted a PR |
Published a new release v1.1.7 Thank you for your contribution! |
@maheshj01 Thanks a lot for integrating this. I can confirm that the error no longer occurs, thus the issue is fixed for me. I still sporadically see message "Null check operator used on a null value" in the console,. but without any negative effect. |
@franzlst sir after entering search text respective suggestions showing then i closed keyboard all the suggestions start from beginning check this https://drive.google.com/file/d/132iZYWgLzDNMllLGyOlkA15SayzkrcZe/view |
@franzlst I will have to reopen this issue, The commit made to fix this issue broke the keyboard functionality #179. I am reverting back that change. |
Describe the bug
I have a strange bug that does not always occur, but which seems to be some kind of race condition. However, it is quite severe and leads to a freeze of the whole Flutter app. So far, I was only able to reproduce it in the web build of my app, not in any debug builds. The error logs are not so helpful:
The error occurs when repeatedly clicking inside and outside of a
SearchField
.However, in the debug builds I was able to sporadically create an error, which might be related to the crash:
By adding some debug print statements, I think I was able to pin down the cause of the exception. The current implementation of
removeOverlay()
is the following:So the overlay is only removed, when it is mounted. This causes the overlay not always to be removed, as the widget might not be removed immediately:
From: https://api.flutter.dev/flutter/widgets/OverlayEntry-class.html
After removing the condition
&& _overlayEntry!.mounted
, I was no longer able to reproduce the issue locally.The text was updated successfully, but these errors were encountered: