title: Flutter: How can i improve that app performance?
body: <p>I want to know why that Flutter code is below 60 fps in some devices (Redmi Go, in that case, profiling mode, showing red bars in UI graph). Is there any way i could optimize it? I began to study Flutter yesterday so i want some tips to help me understand stateful widgets and widgets rendering hierarchy in general.</p>
  
  <p>Thanks in advance.</p>
  
  <p>File <strong>main.dart</strong></p>
  
  <pre class="lang-dart prettyprint-override"><code>import 'package:project/ui/home.dart';
  import 'package:flutter/material.dart';
  
  void main() =&gt; runApp(new MaterialApp(
        home: BillSplitter(),
      ));
  
  </code></pre>
  
  <p>File <strong>home.dart</strong></p>
  
  <pre class="lang-dart prettyprint-override"><code>import 'package:flutter/material.dart';
  
  class BillSplitter extends StatefulWidget {
    @override
    _BillSplitterState createState() =&gt; _BillSplitterState();
  }
  
  class _BillSplitterState extends State&lt;BillSplitter&gt; {
    int _tipPercentage = 0;
    int _personCounter = 1;
    double _billAmount = 0.0;
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text(
            "APP Teste 1.0",
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
          centerTitle: true,
          backgroundColor: Colors.purple.withOpacity(0.5),
        ),
        body: Container(
          margin: EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.1),
          alignment: Alignment.center,
          color: Colors.white,
          child: ListView(
            scrollDirection: Axis.vertical,
            padding: EdgeInsets.all(20.5),
            children: &lt;Widget&gt;[
              Container(
                width: 150,
                height: 150,
                decoration: BoxDecoration(
                    color: Colors.purple.withOpacity(0.1),
                    borderRadius: BorderRadius.circular(12.0)),
                child: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: &lt;Widget&gt;[
                      Text(
                        "Total por pessoa",
                        style: TextStyle(
                            color: Colors.purple,
                            fontWeight: FontWeight.normal,
                            fontSize: 17.0),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(10.0),
                        child: Text(
                          "R\$ ${_calculateTotalPerPerson(_billAmount, _personCounter, _tipPercentage)}",
                          style: TextStyle(
                              color: Colors.purple,
                              fontWeight: FontWeight.bold,
                              fontSize: 35.0),
                        ),
                      )
                    ],
                  ),
                ),
              ),
              Container(
                margin: EdgeInsets.only(top: 20.0),
                padding: EdgeInsets.all(12.0),
                decoration: BoxDecoration(
                    color: Colors.transparent,
                    border: Border.all(
                        color: Colors.blueGrey.shade100,
                        style: BorderStyle.solid),
                    borderRadius: BorderRadius.circular(12.0)),
                child: Column(
                  children: &lt;Widget&gt;[
                    TextField(
                      keyboardType:
                          TextInputType.numberWithOptions(decimal: true),
                      style: TextStyle(color: Colors.purple),
                      decoration: InputDecoration(
                          prefixText: "Total da Conta: R\$ ",
                          prefixIcon: Icon(Icons.attach_money)),
                      onChanged: (String value) {
                        try {
                          _billAmount = double.parse(value);
                        } catch (e) {
                          _billAmount = 0.0;
                        }
                      },
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: &lt;Widget&gt;[
                        Text(
                          "Dividir",
                          style: TextStyle(color: Colors.grey.shade700),
                        ),
                        Row(
                          children: &lt;Widget&gt;[
                            InkWell(
                              onTap: () {
                                setState(() {
                                  if (_personCounter &gt; 1) {
                                    _personCounter--;
                                  }
                                });
                              },
                              child: Container(
                                width: 40.0,
                                height: 40.0,
                                margin: EdgeInsets.all(10.0),
                                decoration: BoxDecoration(
                                    borderRadius: BorderRadius.circular(7.0),
                                    color: Colors.purpleAccent.withOpacity(0.1)),
                                child: Center(
                                    child: Text(
                                  "-",
                                  style: TextStyle(
                                      color: Colors.purple,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 17.0),
                                )),
                              ),
                            ),
                            Text(
                              "$_personCounter",
                              style: TextStyle(
                                  color: Colors.purple,
                                  fontWeight: FontWeight.bold,
                                  fontSize: 17.0),
                            ),
                            InkWell(
                              onTap: () {
                                setState(() {
                                  _personCounter++;
                                });
                              },
                              child: Container(
                                width: 40.0,
                                height: 40.0,
                                margin: EdgeInsets.all(10.0),
                                decoration: BoxDecoration(
                                    borderRadius: BorderRadius.circular(7.0),
                                    color: Colors.purpleAccent.withOpacity(0.1)),
                                child: Center(
                                    child: Text(
                                  "+",
                                  style: TextStyle(
                                      color: Colors.purple,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 17.0),
                                )),
                              ),
                            ),
                          ],
                        ),
                      ],
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: &lt;Widget&gt;[
                        Text(
                          "Gorjeta",
                          style: TextStyle(color: Colors.grey.shade700),
                        ),
                        Padding(
                          padding: const EdgeInsets.all(18.0),
                          child: Text(
                            "R\$ ${(_calculateTotalTip(_billAmount, _personCounter, _tipPercentage)).toStringAsFixed(2)}",
                            style: TextStyle(
                                color: Colors.purple,
                                fontWeight: FontWeight.bold,
                                fontSize: 17.0),
                          ),
                        )
                      ],
                    ),
                    Column(
                      children: &lt;Widget&gt;[
                        Text(
                          "$_tipPercentage%",
                          style: TextStyle(
                              color: Colors.purple,
                              fontSize: 17.0,
                              fontWeight: FontWeight.bold),
                        ),
                        Slider(
                            activeColor: Colors.purple,
                            inactiveColor: Colors.grey,
                            min: 0,
                            max: 100,
                            divisions: 10,
                            value: _tipPercentage.toDouble(),
                            onChanged: (double value) {
                              setState(() {
                                _tipPercentage = value.round();
                              });
                            })
                      ],
                    )
                  ],
                ),
              )
            ],
          ),
        ),
      );
    }
  
    _calculateTotalPerPerson(double billAmount, int splitBy, int tipPercentage) {
      double totalPerPerson =
          (billAmount + _calculateTotalTip(billAmount, splitBy, tipPercentage)) /
              splitBy;
  
      return totalPerPerson.toStringAsFixed(2);
    }
  
    _calculateTotalTip(double billAmount, int splitBy, int tipPercentage) {
      double totalTip = 0.0;
  
      if (billAmount &lt; 0 || billAmount.toString().isEmpty || billAmount == null) {
      } else {
        totalTip = (billAmount * tipPercentage) / 100;
      }
  
      return totalTip;
    }
  }
  
  </code></pre>