Flutter Tutorials – #1.2 – WebView Controller – Completer, Future Builder, Await – Async
Introduction
Welcome to Himdeve development, where we prepare the best tutorials to make your mobile application development easier and more efficient.
Goal
- In this second part of our Flutter series of tutorials, we will add a controller for our WebView to be able to fully control it, such as getting the current url, going forward, backward, refreshing the page, clearing the cache and so on. In our case, we will display the current url address on the screen.
- In addition, we add topBar and floating action button to the application.
- We will learn the difference between the Stateless Widget and the Stateful Widget.
- And also basic info about the concept of Future, FutureBuilder, Completer and Async – Await mechanism in Flutter.
Procedure
First we open our existing application from the previous tutorial and open the file shop_page.dart.
As a first step, we add the Scaffold widget to our ShopPage widget. The Scaffold widget provides a framework that implements the basic material design structure of the visual layout for the Flutter application. It offers an API for displaying appBars, drawers, snack bars, floating buttons, bottom sheet and many other components, and you can also set the background color, add navigation bars, and so on.
In our case, we add the AppBar component to our ShopPage widget, where we set a title of the widget and the floatingActionButton to perform certain actions while the application is running. The Scaffold widget also has a body attribute that draws a hierarchy of other widgets into the canvas. In our case, WebView.
Stateless Widget vs Stateful Widget
We change Stateless Widget to Stateful Widget, so our ShopPage widget will inherit from a StatefulWidget. The constructor remains almost the same except that we skip the const parameter.
The difference between Stateless Widget and Stateful Widget
Stateless Widget
Stateless widgets do not require mutable state, which means they are immutable.
So they cannot change their state while the app is running. This means that widgets that are rendered in this widget hierarchy under the Stateless Widget in the build method cannot be redrawn while the app is running.
The build method is called only once during the application run. The build method is responsible for drawing widgets on the screen. If we wanted to redraw the Stateless Widget, we would have to create a new instance of it.
Stateful Widget
Stateful Widgets have a mutable state and can be rendered on the screen multiple times during one application run.
The Stateful Widget has a createState method by which we return the instance state of the widget, in our case the instance of the private class _ShopPageState. This class inherits from a State object that has a build method, and this method can be called several times while the application is running to redraw the screen.
shop_page.dart
The easiest way to redraw the screen is by using the setState method, which calls the build method, which then renders all widgets in its widget hierarchy.
SetState method
To test how the setState method works in practice, we will create a private _buildChangeTitleBtn method, which will return FloatingActionButton, where we will change the title for this screen from ‘Himdeve Shop‘ to ‘Himdeve Development Tutorial‘.
WebView Controller and Future
Unfortunately, the WebView widget doesn’t work much on the setState method, so if we wanted to change the WebView url from https://himdeve.eu to https://himdeve.com, for example, we need to use the WebView Controller, which has a special method: loadUrl( ‘your_new_url’).
Webview is a widget that must be rendered to the screen and must also initialize its state. This process is asynchronous and takes a short time. However, this means that if we want to directly access the WebView Controller now, it may not be ready yet. It will be ready sometime in future. Therefore, we use the Completer class, which allows us to process Future objects and then complete them with their value or error.
Completer a Future Builder
So in our case the Completer object encapsulates the WebView Controller and we can then check whether the WebView Controller is ready (valid) by calling the _controller.isCompleted method or use the FutureBuilder class, which is actually a widget that is built on the latest snapshot interactions of the future. This means in our case that FutureBuilder will allow us to create new UI widgets such as our FloatingActionButton only after we have prepared our valid WebView Controller.
So we define the encapsulated WebView Controller to completer.
In the WebView object, we set a new attribute onWebViewCreated, which returns the WebView Controller object when it is ready, and we set this object instead of our placeholder in Completer.
We then want to create a method that returns FloatingActionButton, which will display the current url of our WebView page. We call it _buildShowUrlBtn. So we will replace the _buildChangeTitleBtn method with the _buildShowUrlBtn method in the Scaffold widget. And this method returns the FutureBuilder widget of WebViewController, where the Future represents an info about whether the WebView Controller is valid. So it is valid when Completer has data (controller.hasData). Then we will return the FloatinActionButton widget, otherwise we will return the empty Container widget.
Getting url address
The interaction of pressing FloatingActionButton is captured using the onPressed attribute and then the current url address is obtained from the WebView Controller using the command: controller.data.currentUrl ().
Async – Await mechanism
What is important to note here is that the WebView Controller in our completer is a Future object, which means that if we want to get its value in the present, we need to use the async-away mechanism.
Away
This command pauses the running code and waits until the Future is resolved – that is, in our case, until the current url address is obtained from the WebView Controller and then proceeds to the next line.
Async
When using await in a function, this function runs the risk of blocking the main thread and must therefore be marked with the async command to make it asynchronous.
What’s important to note is that the onPressed attribute, which is the FloatingActionButton’s own callback method, is returning void so far, so we can say it does not return anything. But now, by marking it with the async command, it must return the future, in this case Future< Void >. In this example it doesn’t matter, since onPressed basically doesn’t return anything. But if we had a function that returns, for example, an Integer. So once we use the async command, we need to define the return value of the function from Integer to Future< Integer >.
Displaying url address
To display the url address, we use the SnackBar widget. We use its Content attribute, where we set the Text widget with the current url value of WebView, and we set the style for that Text widget to increase the font size.
Scaffold.of(context) means that we will return Scaffold from the closest ancestor of Scaffold in this widget hierarchy, in this case the Scaffold we created for this _ShopPageState class. Then we display the SnackBar using the Scaffold.of(context).showSnackBar function.
Conclusion
And so our second part of this first series of Flutter Tutorials is completed and of course you can find the complete source code on the githube.