Notes: 06. Debug with Android Studio
If the outline pane says “Nothing to show”, just hold down Ctrl on windows or Cmd on mac and click on any class, method or variable to trigger it.
OR Open up the dart analysis panel and restart the dart analysis server. The student materials have been reviewed and are updated as of SEPTEMBER 2022.
So far, we’ve used VS Code to debug our app. Debugging in Android Studio is very similar. Let’s see how to do that.
Open up the starter project for this episode in Android Studio. It pretty much the same code from the previous episode. But this time around, the function passed to the onPressed parameter of the button has been extracted to a new method called sumNumbers.
Run your app in Debug Mode by clicking on the bug icon. Using the run button executes the app but without debugging functionalities. So you always have to run your app in debug mode if you want to use breakpoints and other debugging features.
Once you do that, the debug panel would pop up. This is just like the debug sidebar panel we have in VSCode. Currently, it displays the debug console. I’ll switch to the debugger pane by clicking on the debugger tab.
To add a breakpoint to the first line of the sumNumbers method, click on the line number on the editor margin. This is the same approach just like VSCode. This would pause the execution of our app whenever we get to the start of this method. Let’s try it out.
Execution is paused as expected. In here, we have the breakpoint controls activated. So we could step over, step into, step out of our code.
We also have the Resume program button which is the continue button equivalent in VSCode. As its name suggests, it resumes the execution of our code. Now, we could step into the setState call.
This takes us into the setState method’s definition in Flutter framework. The approach here is quite different from VSCode. In VSCode, it wont navigate to the setState method’s definition simply because this is code from Flutter framework and you wont be changing anything from it.
So let’s step out from this. And it takes us to next line of execution which is the end of the sumNumber method. As you can see, the breakpoint controls works just how you would expect them to. To resume our app’s execution, we hit the Resume Program button. And our ui is rebuilt with the updated UI.
We can also set conditional breakpoints. To do this, you simply right click on the breakpoink then add the condition. So i’ll set the break condition to be when the sum is greater than 300.
And when you click on the done button, the condition would be saved. In VSCode, this is known as expressions but in Android Studio, it is called the condition. I’ll go ahead and remove that now since we dont want a conditional breakpoint.
To disable all breakpoints in your application, you click on the Mute Breakpoints button. And the breakpoints turn grey. Click on the button once more to enable back all breakpoints. And they turn back to red.
To view all breakpoints in your app, click on View Breakpoints button. This opens up a window that shows you all breakpoints in your application. Currently, we have the Dart Exception Breakpoint enabled. And over at the open we have the Dart Line exception which contains all line breakpoints we manually set. And we can see the one we addded.
Over here, we have a quick view section that shows you where you set it in code. We can also enable conditions and perform other breakpoint specific operations. The Breakpoints window, gives your more tools to further customize your breakpoints. I’ll go ahead and close it.
To inspect and watch variables, we use the Variables panel in the debugger. Click on the add button once more. And this triggers our breakpoint. The variables panel is currently empty.
Go ahead and step over the call to setState. This populates it with an instance of the State object we’re working with. It is represented by the variable named this. Let’s open it up.
In here, we have different properties of the state object and we can see the sum variable stored too. This is the same approach with VSCode where VSCode adds the instance of the State object in locals section of the variables panel.
Next, resume the execution of the app. To watch a variable so that we can monitor its changes, click on the plus icon and add in the variable.
I’ve added in the sum variable here. Next, i’ll remove the breakpoint at the setState line and add a new one at the end of the method which is the line that has the closing brace. Then I’ll change up the values of the text fields and hit the add button once more.
And you can see that the sum watcher is populated with the value of sum. Let’s resume the app. And the UI updates acccordingly.
The final section we’ll be covering in the debug panel is the frames pane. Hit the add button once more. The frames pane is Android Studio’s equivalent of the call stack section in VSCode’s debugger. They’re both the same thing and this shows the path of different function calls leading to the current execution point. Currently, we’re in the sumNumbers method and you can see it is at the top of the frame.
I’ll go ahead and resume the execution of our app. Then I’ll hide the debug panel. And I’ll also remove this breakpoint. Android Studio provides us with additional debugging functionalities. You can see them docked at the right side of Android Studio. These tools offers more debugging and profiling utilities for our Flutter apps.
The Flutter inspector is used to monitor and inspect the configuration of the widgets in our app. It can be usefule when debugging layout related issues.
The Flutter outline is not really a debugging tool. It just shows us our source code in a tree like manner and gives us quick access to navigate to specific code.
Finally, the Flutter performance tab gives us utilities to check how smooth our app renders and this is done by calculating the frame rate. A frame rate here is simply how many images of our UI that Flutter draws or renders to our screen in one second. 60 frames per second is optimal. The higher the number, the smoother your app would run.
In debug mode, you’ll get lower frame rates and you can see the frame rate here fluntuates around 30fps. So you’ll have to run your app in profile mode on a real device to get the correct frame rate. The performance tab also shows us the memory usage and how much a widget rebuilds.
Let’s explore the widget rebuild stats. To track how many times a widget is rebuilt, click on the “Track widget rebuilds” checkbox to enable it. Then you do a hot restart.
This feature is useful when you want to track unnecessary widget rebuilds that could be affecting the performance of your apps. Flutter handles this so you dont need to worry about this unless the number becomes very high.
As you can see, all widgets are being built only twice since we just hot restarted our app. The value can be between one or two after hot restart. Let’s fill up the form and submit it to see what happens. You can see some widgets were rebuilt.
The MaterialApp and MyApp widgets were not rebuilt simply because these widgets are higher
in the widget tree and the build method that was triggered is contained in the MyHomePage widget which is down below the tree. So only descendants of the MyHomePage widget are candidates for a widget rebuild.
Let’s scroll to the sum text widget. And you can see that this text widget is built only once.
And this is because we have a condition here which prevents the text widget from being mounted until sum is not null. So previously, this text widget was not in the widget tree. But after we clicked on the add button, it was inserted to the widget tree, hence building only once.
We can also view the number of rebuilds on the editor margin beside the line number. You can see a grey icon and if we hover over it, you can see the rebuilds information. And you can see that this text widget was built only once.
A grey circle is displayed for widgets that are not rebuilt, otherwise, you’ll see a grey spinning circle. A yellow spinner is dispayed if the rebuild value is very high. This is a sign that you need to refactor your widgets for example, splitting a larger widget into smaller stateless widgets or check other factors that could be causing a high rebuild.
Remember, all these stats are available because we enabled “Track widget rebuilds.” So I’ll go ahead and uncheck it. Note: As of the time of this recording, “The Widget Rebuild stats” is only available in the Flutter plugin for IntelliJ and Android Studio.
We would explore the Flutter Inspector and other debugging features in the next episode. And for this, We would be using Dart DevTools which is a debugging utility for Flutter apps.