Refresh indicator sometime did not perform the action - flutter

I have one refresh indicator in which I print something. When I drag the refresh indicator sometimes it prints the statement but sometimes I drag the refresh indicator it just moves up quickly and does not perform anything.
I do not know why this strange behavior or what I am missing.
RefreshIndicator(
onRefresh: () async {
print("I am refresshing the data");
await some APi call
};
child:Listview.builder();

Create a function and pass it to onRefresh. And In that function, you should perform your task.
onRefresh: refreshList
Future<Null> refreshList() async{
await Apicall();
}
Apicall(){
//write api call
}

Related

Why is my function preventing the dialog dismiss/pop in Flutter?

I am trying to execute a function after a dialog is dismissed/popped. I read this article How to run code after showDialog is dismissed in Flutter? and tried to do it as recommended but it wouldn't work for me.
This is how I call my dialog:
Future<void> onDeleteEventData(BuildContext context) async {
final title = context.messages.settings.offline.deleteEventData;
final subTitle = context.messages.settings.offline.deleteEventDataDesc;
final res = await showDeleteDialog(context,
title: title,
subTitle: subTitle);
if (res == true){
context.read<EventDownloadTileController>().deleteEventRelatedData();
}
}
The showDeleteDialog function just calls a custom Dialog which is basically just the Flutter Dialog with some style changes.
Future<bool?> showDeleteDialog(BuildContext context,
{required String title, String? subTitle}) async {
return await showDialog(
context: context,
builder: (_) => DeleteDialog(title: title,subTitle: subTitle,)
);
}
In the dialog I press on a button and do this:
onPressed: () => Navigator.of(context).pop(true),
So looking at the first function I wait for my res which evaluates to true. At this point I thought the dialog should be popped. But it is not.
The problem is this call:
context.read().deleteEventRelatedData();
Because when I replace this call with e.g. Future.delayed(duration(seconds:5)); the dialog pops right away as expected.
This is the function:
Future<void> deleteEventRelatedData() async {
_ticketLoader.stop();
_ticketStorage.deleteScanTicketsForEvent(event.eventId);
_eventStorage.deleteEventPermissions(event.eventId);
_eventStorage.deleteEventData(event.eventId);
_ticketStorage.deleteCachedTicketsForEvent(event.eventId);
_ticketStorage.deleteCachedUnknownTicketsForEvent(event.eventId);
_ticketLoader.updateLastSync(null);
_ticketLoader.reset();
checkLocalStatus();
}
A function with some async and synchronous functions. The execution takes up to 3 seconds which is the time it takes to dismiss/pop my dialog. But I want to pop the dialog right away and let it work in the back. What could my function possibly do for this behavior?
Thanks in advance
The dialog window isn't going to disappear until the app can manage to do a rebuild. If your function call takes a while, it could be hogging the main thread until it's complete, disallowing other code (including widget code) from running.
Try wrapping your function call in a microtask so it doesn't run until the next available task window which will give the app time to clean up the dialog window:
await Future.microtask(deleteEventRelatedData);
It's also worth mentioning the body of the deleteEventRelatedData is marked as async but it never awaits anything. That means all of the synchronous calls can happen in a sequence that wasn't intended and the asynchronous calls won't get executed until a later time and in no guaranteed order.

Riverpod - How to refresh() after an async function completes after the user has already left the screen

I have a Flutter app that has a screen with a ListView of items that is supplied by a provider via an API call. Tapping an item goes to a second "detail" screen with a button (onPressed seen below) that will make an API call to complete an action. On success, the item is removed from the list by running refresh() to make the first API call again to get an updated list. However, if the user navigates away from the detail screen before the action is completed, executing the refresh is no longer possible and will throw the "Looking up a deactivated widget's ancestor is unsafe" exception. This is why I am first checking the mounted property, but is there any way in this scenario to execute the refresh? I am trying to avoid the confusion of the user seeing an outdated list and having to manually refresh. Thanks.
onPressed: () async {
setState(() {
// Disable the submit button
});
someAsyncFunction().then(
(success) {
if (!mounted) {
return;
}
if (success) {
// Success snackBar
ref.refresh(someProvider);
Navigator.pop(context);
} else {
// Failure snackBar
setState(() {
// Re-enable submit button
});
}
},
);
}

ListTile not getting updated with Google Places API in flutter

I have this method which gets a suggested place through the Google Places API based on the user input.
void getSuggestion(String input) async {
var googlePlace = GooglePlace(AppConstants.APIBASE_GOOGLEMAPS_KEY);
var result = await googlePlace.queryAutocomplete.get(input);
setState(() {
_placeList = result!.predictions!;
});
}
_placeList is filled properly, but it does not get updated instantly, I have to hot reload to see the changes whenever I change the query value in my TextController:
TextField(
onSubmitted: (value) {
setState(() {
getSuggestion(value);
showDialog(
context: context,
builder: ((context) {
return Card(
child: ListTile(
title: Text(_placeList[0].description),
),
);
}));
});
},
For example, if I search for "Miami" I get the recommendation on my listTile, but if I change it to "Madrid" it still appears "Miami" and I have to reload screen to see the change.
I do not understand because I am setting the state in my method.
getSuggestion is an asynchronous function. In other words, in the following code snippet:
getSuggestion(value);
showDialog(
context: context,
...
After invoking getSuggestion, it does not wait the function to finish before showing the dialog. In other words, when the dialog is shown, maybe the previous function hasn't completed yet, so that _placeList is not updated yet.
Firstly, it is a better idea to get rid of setState within getSuggestion as it is redundant to do it twice.
Secondly, in the onSubmitted lambda, make the anonymous function async (onSubmitted: (value) async { ...), then wait for getSuggestion to finish by await getSuggestion() (do not await inside setState). At this point, _placeList is updated, and you can invoke setState now, things should rebuild properly if there are no other errors.

How to call a function when returning to view/controller with `Get.back()`?

I am switching from the home view to another using Get.toNamed(Routes.DETAIL). When I want to return from the details view to the home view, I am calling Get.back() (or the user is using the back button of the devices).
Back on the home view, I would like to fetch all data from my database again.
Is there any function that is triggered when I am leaving a few and returning to it, so I can put my logic there?
Thank you
I would suggest you to use Get.offNamed() instead of Get.toNamed() as the offNamed() function will clear the data stored in catch and thus will again call the API declared in onInit() or onReady() lifecycle when returning back to that screen.
In Getx they have a funtion like
Get.back(result:"result");
so in order to trigger some funtion when going back to any page route
try doing this as the document written
final gotoHome = await Get.toNamed(Route.name); // or use the simple one Get.to(()=> Home());
then if you trigger to go back in page you should indicate some result e.g.
from back button in phone using willpopscope or a back button in UI.
Get.back(result:"triggerIt"); // this result will pass to the home.
so in will use
// It depend on you on where you gonna put this
// onInit or onReady or anything that would trigger
someTrigger() async{
final gotoHome = await Get.toNamed(Route.name);
if(gotoHome == "triggerIt"){
anyFuntionYouwantoTrigger();
}
}
for more info about it try to read the documentation.
https://github.com/jonataslaw/getx/blob/master/documentation/en_US/route_management.md
Edited: // Maybe some answer will pop up for better
I do have one but it's not that quite a real practice just a sample
e.g // sample you are now in the current page and this page is also connected to homecontroller or using Get.find() it need to bind the controller to the page;
class BindingHome with Bindings{
#override
void dependencies() {
Get.lazyPut(() => HomeController(), fenix: true);
}
}
then from GetPage add Binding
GetPage(
name: "/currentpage",
binding: BindingHome(),
page:() => HomeView(),
),
so while homecontroller is bind to the current page you are now so
// lets assume this one is put to the CurrentController
final homeController = Get.find<HomeController>();
so while calling back button on ui or willpopscope
when back try to trigger the function from home
gotBackfunction(){
Get.back();
homeController.anyFuntionYouwantoTrigger();
}
No you can't really call a function when doing so.
You should be using callback function just before popping the view.
onBackClick() async {
Get.lazyPut<MainController>(
() => MainController(),
);
controller.allItems.refresh();
Get.back();
}
Here is an example how you can do it without any complications:
WillPopScope(
onWillPop: () async {
await onBackClick();
return Future(() => false);
},
child: Scaffold(
appBar: CustomAppBarWithBack(
title: "Appbar",
OnClickBack: onBackClick,
),
body: Widget(),
),
);

perform a navigation inside the build method of a widget? - flutter

Fast question: how can I perform a navigation inside the build method of a widget?
I'm developing a Flutter App.
I use Bloc architecture.
I have screen with a create form. When the user presses a button, it calls a REST api. While the call is being executed I display a circular progress. When the progress ends I want the screen to be popped (using navigation).
To display the job status I use a Stream in the bloc and a StreamBuilder in the widget. So I want to do something like this:
return StreamBuilder<Job<T>>(
stream: jobstream,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.jobStatus == JobStatus.progress)
// job being executed, display progress
return Center(child: CircularProgressIndicator());
else if (snapshot.data.jobStatus == JobStatus.success)
Navigator.pop(context); // Problem here!
return Center(child: CircularProgressIndicator());
} else {
return DisplayForm();
}
});
I have problems with the line: Navigator.pop(context);
Because navigation is not allowed during a build.
How can I do this navigation?
My currect dirty solution is using the following function, but its ugly:
static void deferredPop(BuildContext context) async{
Future.delayed(
Duration(milliseconds: 1),
() => Navigator.pop(context)
);
}
You can add a callback to be executed after the build method is complete with this line of code:
WidgetsBinding.instance.addPostFrameCallback((_) => Navigator.pop(context));
'Because navigation is not allowed during a build.' that being said you should consider creating a separate function that will receive as an input something that you will take into consideration whether to pop that screen.