Mastering Dart & Flutter DevTools — Part 4: Network View

Flutter Gems
11 min readDec 28, 2022

by Ashita Prasad (LinkedIn, Twitter), fluttergems.dev

This is the fourth article in the “Mastering Dart & Flutter DevTools” series of in-depth articles. In this article, you will learn about the DevTools’ Network View tool using a real-life example. In case you want to check out any other article in this series, just click on the link provided below:

Installation and setup of DevTools is a pre-requisite for this part. In case you missed it, the installation and setup details are provided in detail here.

Apps frequently use the internet to authenticate users, access network resources, make API calls and connect to backend servers or services. This network activity has a direct impact on the user experience as lower latency leads to better app responsiveness and makes the user believe that the app is faster.

Monitoring the network traffic can help us:

  • Identify bottlenecks and other performance issues in an app’s network communication.
  • Inspect client-server API interactions between the app and backend.
  • Identify if any unidentified/malicious network request is being made by any 3rd-party package.
  • Identify if there is any increase in network activity due to redundancy in API requests that are being made.
  • Analyze and reduce the app mobile data usage as it is expensive.

In this this article, we will walk through Devtools’ Network View tool and witness how it can be used to monitor the existence of any of the above mentioned problems in our Flutter app.

Network View

Network View tool helps us monitor and inspect any HTTP, HTTPS or web socket traffic from a Dart or Flutter application.

To better understand the utility of Network View tool, let us undertake a case-study exercise.

Step 1: Getting the Source Code

Open the below mentioned repository.👇

Open the repo in GitHub as shown below.

Click on the green button <> Code, then visit the Local tab and click Download ZIP to download the source code for this exercise.

Extract the file using any unzip tool.

We now have a local copy of the source in the folder network_view_demo-master.

Step 2: Opening the Project in VS Code

Launch VS Code, open the project folder in VS Code and go to pubspec.yaml file.

Click on Get Packages to fetch all the packages required for this project.

Click Get Packages

Step 3: Launching Network View in VS Code

Before we launch the Network View tool, we must run the app.

Click on No Device in the status bar and select a target device. If a default device is already selected, you can click on it and change the target device.

Select Target Device

We will go ahead and select an android emulator as the target device.

android emulator selected as target device

Now, click Run to run the app (main function) as shown in the image below.

Run the app

Now, Network View can be launched using the following instructions:

Click Dart DevTools in status bar > 
Click Open DevTools in Web Browser > Click Network tab
Opening Network View

If you take a look at the bottom of the page, a circular progress indicator is visible, which indicates that the network traffic is being recorded.

Current Monitoring Status

You can pause the monitoring of network traffic by clicking on the Pause button on the top-left corner of the page.

Pause, Resume & Clear Buttons

Similarly, you can resume the monitoring by clicking Resume and clear the existing network traffic log using the Clear button.

Step 4: Monitoring Network Traffic

Once you run the application, you will be presented with the main screen containing two buttons to launch the following two scenarios:

  • Scenario #1 — In this scenario, we make API requests fetching different types of responses and monitor the network traffic using Network View.
  • Scenario #2 — After investigating the network traffic in Scenario #1, we make requisite changes to optimize the network activity resulting in better app performance.
Demo App Home Screen: Two Scenarios

So, let us get started with Scenario #1.

Scenario #1

Keep the Network tab open and click on Launch Scenario #1 button.

It loads the first scenario page (as shown below), that contains a Scaffold, with a single card in the body. The card contains a thumbnail and a text. There is also a floating action button at the bottom.

Scenario #1

If we take a look at the network traffic, two GET requests have been made to external URLs — jsonplaceholder.typicode.com and via.placeholder.com.

Network Traffic

Now let us take a look at the code to understand why these requests are being made.

@overrideWidget build(BuildContext context) {...    body: FutureBuilder(              future: getData(),              builder: (context, AsyncSnapshot<dynamic> snapshot) {...

When the widget is built for the first time, FutureBuilder calls the getData() function and awaits for the results of this future.

Future<dynamic> getData() async {    var response = await http.get(      Uri.parse("https://jsonplaceholder.typicode.com/photos"),    );    if (response.statusCode == 200) {          return jsonDecode(response.body);    } else {          throw Exception('Failed to load photos');    }}

If we take a look at the getData() async function above, we can see that a HTTP GET request is being sent to the API server using the get() function provided by the dart http package. The request URL https://jsonplaceholder.typicode.com/photos is highlighted in the image below.

1st API Request

The next GET request is sent by the Image.network widget (see code below) that loads an image thumbnail from the given URL resource — https://via.placeholder.com/150/92c952

return Card(    child: ListTile(               leading: Image.network(cardData['thumbnailUrl']),               title: Text(cardData['title']),     ),);

In the Network View, we can select any network request from the table in the left to view further details on the right side pane.

Let us select the https://jsonplaceholder.typicode.com/photos request.

As shown below, we can inspect general information, timing information, request & response headers, and the content of the response which in this case is a list of 5000 items where each item represents the data corresponding to a photo having an albumId , id , title , url and thumbnailUrl.

API Request #1 Details

We can cross-check the details (title and thumbnail URL) of the visible card item as shown below.

Visible Card Item

The details are same as the details of the first map item shown in the response data below.

First Map Item

Now, let us click on the second GET request that was made to https://via.placeholder.com/150/92c952 to fetch the thumbnail.

As shown below, apart from the other details, this time the response tab also displays the fetched image along with the image metadata. Thus, we can easily view a wide variety of response data using this tool be it text, json or image.

API Request #2 Details

When we first launch the Scenario #1 page, only a single card is visible as the value of _counter is initialized as 1 which represents the number of items the list view builder can create.

On clicking the floating action button we can increment the value of the _counter to display more cards using the _incrementCounter() method.

void _incrementCounter() {    setState(() {        _counter++;    });}

Let us go ahead and press the floating action button to add new items to the list view and observe the network traffic.

Add new item by pressing the Floating Action Button

On inspecting the network traffic as shown below, we can observe that data API request https://jsonplaceholder.typicode.com/photos is being made repeatedly.

API Request #1 made repeatedly

This is because the FutureBuilder is connected to the asynchronous computation function getData(). As this future is created at the same time as the FutureBuilder, every time the widget is re-built due to any change in the state, the asynchronous task restarts. Thus, getData() method is executed repeatedly and a new photo data API GET request is made every time the floating action button is clicked. Not only this leads to the same data being fetched repeatedly, but also due to this increased network activity the app response is slow as we can see a circular progress indicator after each click.

In this scenario, we can see how network traffic can cause the app to appear less performant due to unnecessary network traffic.

The best practice to avoid such repeated API calls is to avoid creating and calling a future in the build() method, i.e., the future associated with FutureBuilder should be computed outside the build() method.

Let us take a look at Scenario #2 that addresses this problem.

Scenario #2

The source code and setup instructions for this scenario is same as the Scenario #1.

Run the app and click Launch Scenario #2 button.

When the screen loads for the first time, the requests made are same as Scenario #1.

Scenario #2 Page

But, now when we press the floating action button to add more Cards, no more requests are being made to fetch the photo data and only the placeholder image requests are made.

Scenario #2 Network Traffic after pressing the Floating Action Button

Let us now take a closer look at the code of Scenario #2.

The repeated API request problem was solved by calling getData() in the initState() method that is called only once before the first build. In this case the result of the future getData() is stored in the state variable _data.

class _Scenario2PageState extends State<Scenario2Page> {
...
late Future<dynamic> _data; ... @override void initState() { super.initState(); _data = getData(); } ...

One must note that the value of _data is a future that may or may not have completed, i.e., made any HTTP request to fetch the required data. So we still need to use the FutureBuilder widget and associate the future _data to it.

     @override     Widget build(BuildContext context) {          ...             body: FutureBuilder(                future: _data,          ...

Hence, when the build() is executed, FutureBuilder waits for the completion of all async tasks that lead up to the evaluation of the final value of the future _data. This is done only once.

Now, every time we press the floating action button, the build() method is triggered. But, as the value of future _data is now available in the current state, data API requests are no longer being made and only the placeholder image requests are being sent.

Thus, in Scenario #2, we were able to detect and resolve the redundant network traffic observed in Scenario #1. As the future is now being computed outside the build method, we are no longer making any redundant API requests.

Some Additional Features — Search, Filter & Copy

Network View also provides some additional features like Search & Filter to navigate the network traffic results.

In the Scenario #2 Network View tab, let us enter a search string that might occur in the URI column. In this case, we will enter the term via.

Search box

All network traffic URI containing the term via is highlighted as shown below. Now, you can easily click on the request and view more details.

All requests containing ‘via’ is highlighted

Another advanced feature that is located just beside the Search tool is the the Filter tool.

FIlter

On clicking the button, a dialog pops up with the instructions to construct a filter query as shown below.

Filter Tool Popup Dialog

Following the instructions, we can create a filter query like type:png as shown in the image below to view all png image requests we made.

Filter Query — type:png

Viola! All requests with response type png are displayed (image below) and traffic of any other type is hidden.

Only Requests with Response Type png is visible to inspection

For each request, we also have the option to copy it as cURL.

Copy as cURL

The above cURL request copied above is as follows:

curl --location --request GET 'https://jsonplaceholder.typicode.com/photos' \--header 'user-agent: Dart/2.18 (dart:io)' \--header 'accept-encoding: gzip' \--header 'content-length: 0' \--header 'host: jsonplaceholder.typicode.com'

These Network View features — Search, Filter & Copy, are very useful for locating the API requests originating from our Flutter app, so that you can use your favourite API debugging or development tool to perform any further analysis.

In this article, we witnessed how DevTools’ Network View tool can be used to monitor and analyze the network traffic of a Flutter app using two scenarios:

  • In Scenario #1, we performed a detailed analysis of the API traffic generated by the app.
  • In Scenario #2, we rectified the redundant API requests that were being made in Scenario #1, leading to an improvement in the responsiveness of the app.

We would definitely love to hear about your experience with the Network View tool and any other suggestions in the comments. In case you faced any issues while going through this exercise or while running the tool for your project, please feel free to mention it in the comments and we can definitely take a look at it.

In the remaining articles of this series, we have discussed other tools available in the DevTools suite that can help you build high-performance Flutter apps. Don’t forget to check out the links below to navigate to the tool you want to learn next:

Source Code(s) used in this article:

Special thanks to Kamal Shree (GDE — Dart & Flutter) for reviewing this article.

--

--

Flutter Gems

Maintained by Ashita Prasad, Flutter Gems is a curated package guide for Flutter ecosystem. Visit https://fluttergems.dev