I am building an app which has local database and I keep some infos about movies in that database. There is a screen called "Favorites" where I get the movies from local database and put them in a listview:
And if I click any movie from that list, I will be directed to a new Screen where I can see movie details. In this screen, there is a button which removes the movie from local database.
Now my problem starts here: After I remove any movie from database and go back to "Favorites" Screen, I still see that movie in ListView. But I have already removed that movie from database. If I was doin this on Android platform, I would override onStart method and make a query to database, then update the listview. But in Flutter as long as I know, there is no method as onStart. So, what should I do?
class FavoritesScreen extends StatefulWidget {
@override
_FavoritesScreenState createState() => _FavoritesScreenState();
}
class _FavoritesScreenState extends State<FavoritesScreen> {
var favoriteMovieDatabase = FavoriteMovieDatabase();
List<MovieOverview> movieOverviewList = List<MovieOverview>();
@override
void initState() {
super.initState();
favoriteMovieDatabase
.getAllFavoriteMovies()
.then((List<MovieOverview> list) {
setState(() {
movieOverviewList = list;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Favorites")),
body: MovieOverviewListView(movieOverviewList, "FAVORITE")
);
}
}
EDIT:
I have tried to use WidgetsBindingObserver but it did not help.
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if(state == AppLifecycleState.resumed){
favoriteMovieDatabase
.getAllFavoriteMovies()
.then((List<MovieOverview> list) {
setState(() {
movieOverviewList = list;
});
});
}
}
It did not even call this method.
As a simple solution, you can await the result of a navigator push:
goToDetailPage(BuildContext context) async {
await Navigator.of(context).pushNamed('movieDetail');
// this is reached when the route is popped
reloadData();
}
To make the code even more efficient, you can return a result from your detail route that signifies if the movie was deleted:
Navigator.pop(context, 'MOVIE_DELETED');
and
goToDetailPage(BuildContext context) async {
final result = await Navigator.of(context).pushNamed<String>('movieDetail');
if(result == 'MOVIE_DELETED') {
reloadData();
}
}
In the long run, when there are more ways to change the database content (think of a semitransparent dialog where the movie list is still visible in background, or live updates), it would be better to move to some kind of reactive architecture similar to Room on Android.
Assuming your problem happens when you use Navigator
to push a new route, then you can use RouteAware
mixin combined with RouteObserver
and then overrides didPopNext
method.
didPopNext
is called whenever a route becomes visible again.
final RouteObserver<PageRoute> routeObserver = new RouteObserver<PageRoute>();
void main() {
runApp(new MaterialApp(
home: new Container(),
navigatorObservers: [routeObserver],
));
}
class RouteAwareWidget extends StatefulWidget {
State<RouteAwareWidget> createState() => new RouteAwareWidgetState();
}
// Implement RouteAware in a widget's state and subscribe it to the RouteObserver.
class RouteAwareWidgetState extends State<RouteAwareWidget> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context));
}
@override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
@override
void didPopNext() {
// TODO: query DB again
}
@override
Widget build(BuildContext context) => new Container();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With