介紹性能檢測工具 Observatory 、DevTools的基礎(chǔ)使用及測試用例

目的

介紹Flutter的性能檢測工具Observator、DevTools的如何使用,同時提供了一個Demo測試用例來檢測APP性能的提升情況

工具使用

不管是vsCode還是Android Studio都提供了觀測臺的功能。

  • Observator
    打開的方式一般都是在terminal中輸入flutter run,如果要使用真機(jī)測試則輸入flutter run --profile。成功后會出現(xiàn)如圖所示的網(wǎng)址,打開該網(wǎng)址



  • DevTools
    輸入命令行flutter run --profile將程序跑起來后,打開DevTools會出現(xiàn)如圖所示的網(wǎng)頁,不要用Safari及其他瀏覽器中打開,因為DevTools只支持用Chrome瀏覽器打開。



    一般我們使用的都是Observatory的timeline部分。
    一般在timeline中,我們一般選用Flutter Developer的選項。出現(xiàn)的渲染顯示我們一般會看到gpu和ui的渲染,以及重構(gòu)過程。



性能優(yōu)化

在性能優(yōu)化之前,我們需要知道Flutter重構(gòu)的邏輯。
在Android中我們知道繪制需要的三個步驟是measure、layout、draw,
在iOS中UIView繪制可參考iOS-UI繪制原理
而Flutter對應(yīng)的是build、layout、paint。
Flutter的重構(gòu)是基于一種標(biāo)臟和重新創(chuàng)建的方式進(jìn)行的,所以我們的性能影響一般來自于一個復(fù)雜界面的不斷重建??赡苣阒恍枰薷囊粋€很小的部分,也就是很小的一個子樹需要進(jìn)行修改,那么在代碼沒有規(guī)范的情況下,可能會出現(xiàn)整個界面的刷新,這樣我們的性能可能就要下降了數(shù)倍。
對于我的代碼而言,就是整個界面的代碼都得到了重建的,但是這是基于本身代碼還是簡單的原因,如果代碼是非常復(fù)雜的,對應(yīng)用的性能就會產(chǎn)生極大的影響。


上文的意思用這張圖來表示,本來我們只想重構(gòu)的是畫綠叉的子樹,但是由于代碼書寫的原因,導(dǎo)致的結(jié)果是重構(gòu)了畫紅叉的整棵樹。所以代碼的書寫規(guī)范在性能優(yōu)化上起了至關(guān)重要的作用。

代碼測試

import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class Test extends StatefulWidget {
  @override
  State createState() => _Test();
}

class _Test extends State<Test> {
//  int _num = 0;

//  @override
//  void initState() {
//    // TODO: implement initState
//    super.initState();
//    Timer.periodic(Duration(seconds: 1), (timer) {
//      setState(() {
//        _num = timer.tick;
//      });
//    });
//  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("test"),
      ),
      body: Column(
        children: [
          _buildTop(),
          _buildMiddle(),
          // Bottom
//          Flex(
//            direction: Axis.horizontal,
//            children: [
//              Expanded(
//                  flex: 1,
//                  child: Card(
//                    color: Colors.black26,
//                    child: Container(
//                      padding: EdgeInsets.fromLTRB(0, 100, 0, 100),
//                      child: Center(
//                        child: Text("$_num"),
//                      ),
//                    ),
//                  )),
//            ],
//          ),
          BuildBottom()
        ],
      ),
    );
  }

  Widget _buildMiddle() {
    return SizedBox(
      height: 150,
      child: ListView.builder(
        itemCount: 3,
        scrollDirection: Axis.horizontal,
        itemBuilder: (context, index) {
          return Card(
            child: Container(
              padding: EdgeInsets.fromLTRB(100, 0, 100, 0),
              child: Center(
                child: Text("Middle First"),
              ),
            ),
            color: Colors.amber,
          );
        },
      ),
    );
  }

  Widget _buildTop() {
    return Card(
      child: Text("Top"),
    );
  }
}

class BuildBottom extends StatefulWidget {
  @override
  State createState() => _BuildBottomState();
}

class _BuildBottomState extends State<BuildBottom> {
  int _num = 0;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {
        _num = timer.tick;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Flex(
      direction: Axis.horizontal,
      children: [
        Expanded(
            flex: 1,
            child: Card(
              color: Colors.black26,
              child: Container(
                padding: EdgeInsets.fromLTRB(0, 100, 0, 100),
                child: Center(
                  child: Text("$_num"),
                ),
              ),
            )),
      ],
    );
  }
}

上圖是我測試的代碼,黑框中的數(shù)據(jù)是通過定時器Timer自動更新的。

int _num = 0;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {
        _num = timer.tick;
      });
    });
  }

在initState()函數(shù)中,我們做了一件事情,就是一個初始化,并且讓黑框中數(shù)字每1s進(jìn)行一次更新。
在源碼中,這個數(shù)據(jù)更新處于兩種位置:Main頁面、組件化的BuildBottom。

  • Main頁面:在這個頁面中,如果重構(gòu),就會發(fā)生我們上述所說的情況,把整個頁面全部重構(gòu)了。
  • 組件化的BuildBottom:將上述的更新代碼轉(zhuǎn)移到這個組件中,那么重構(gòu)的效果就會和上述的一樣,當(dāng)然你還可以進(jìn)行細(xì)化。


    性能優(yōu)化前

    性能優(yōu)化后

    通過Observatory的觀測,我們能夠看到兩種位置進(jìn)行了更新,他們重構(gòu)所需要進(jìn)行的步驟是完全不一樣的程度,況且該Demo的頁面邏輯還處于一個比較簡單的狀態(tài),如果是復(fù)雜頁面的話開銷則會非常龐大,對性能的影響就會比較明顯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容