📜  颤振 package_info 没有获得内部版本号 (1)

📅  最后修改于: 2023-12-03 14:58:48.147000             🧑  作者: Mango

颤振 package_info 没有获得内部版本号

当程序员使用Flutter开发时,偶尔会遇到警告"颤振 package_info 没有获得内部版本号"。这篇文章将为您解释何为"颤振",以及该警告的原因和解决方法。

什么是“颤振”?

颤振(jitter)是指时间上的不规则抖动。在Flutter中,当某些widget的属性值改变后,如果它们不仅仅改变了呈现的外观,还改变了布局大小和位置,就会导致其它widget出现颤振。颤振可以使布局看起来比较不稳定,影响用户体验。

为什么会出现“颤振 package_info 没有获得内部版本号”的警告?

Flutter的package_info库是用来获取应用程序信息的库。当某些widget使用了该库的信息,并且在每次build时,package_info版本号都被请求了两次(一次android版本号和一次ios版本号)时,就会出现上述警告。

虽然该警告不会导致应用程序崩溃或错误,但它表明了Flutter Engine更新的一个潜在风险,因此应该尽快解决。

如何解决“颤振 package_info 没有获得内部版本号”?
方法一

一种解决方法是使用FutureBuilderValueListenableBuilder来请求package_info的版本号,在此之前,我们需要考虑到哪个部件的哪个属性需要 package_info 的信息。

import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';

class PackageInfoWidget extends StatefulWidget {
  @override
  _PackageInfoWidgetState createState() => _PackageInfoWidgetState();
}

class _PackageInfoWidgetState extends State<PackageInfoWidget> {

  Future<PackageInfo> packageInfo;

  @override
  void initState() {
    super.initState();
    packageInfo = PackageInfo.fromPlatform();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<PackageInfo>(
      future: packageInfo,
      builder: (BuildContext context, AsyncSnapshot<PackageInfo> snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return Text('Version ${snapshot.data.version}');
        } else {
          return CircularProgressIndicator();
        }
      },
    );
  }
}

该代码的作用是在app中显示package_info的版本号,并且使用了FutureBuilder。该方法可以在应用程序布局没有改变时避免颤振。

方法二

另一种解决方案是使用dart:ui库中的FrameTimingVsync类。以下是一个使用该方法的示例:

import 'dart:async';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';

class PackageInfoWidget extends StatefulWidget {
  @override
  _PackageInfoWidgetState createState() => _PackageInfoWidgetState();
}

class _PackageInfoWidgetState extends State<PackageInfoWidget> with SingleTickerProviderStateMixin{

  PackageInfo packageInfo;

  AnimationController _animationController;
  Timer _timer;
  Duration animationDuration = Duration(milliseconds: 500);

  //总帧数
  int frameCount = 0;
  //版本号
  String version = '';

  //触发帧回调
  void _onFrame(Duration timeStamp) {
    //计算两次回调时间间隔
    final elapsed = _animationController.lastElapsedDuration ?? Duration.zero;
    final deltaTime = timeStamp - elapsed - _animationController.startTimestamp;
    final frameTiming = FrameTiming(
      vsyncTimeStamp: Duration.zero,
      buildFinishTimeStamp: Duration.zero,
      buildDuration: deltaTime,
      rasterDuration: Duration.zero,
      vsyncOverhead: Duration.zero,
      totalSpan: deltaTime,
    );
    //记录总和
    frameCount++;
    //如果帧率相当于每秒60桢,我们开始减速以避免出现颤振
    if (frameCount % 60 == 0) {
      _animationController.stop(canceled: false);
      _timer = Timer(Duration(milliseconds: 150), () {   //延时150ms启动
        _animationController.repeat(period: animationDuration, reverse: true);
      });
    }
    //获取package_info版本号
    PackageInfo.fromPlatform().then((value) => version = value.version);
    //输出版本号
    _output(targetFrameTiming: frameTiming);
  }

  //输出
  void _output({FrameTiming targetFrameTiming}) {
    if (targetFrameTiming.buildDuration > animationDuration) {
      setState(() {});
      _animationController
              .duration = (targetFrameTiming.buildDuration ~/ animationDuration) *
          animationDuration;
    }
  }

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(vsync: this, duration: animationDuration);
    _animationController.repeat(period: animationDuration, reverse: true);
    window.onBeginFrame = _onFrame;
  }

  @override
  void dispose() {
    super.dispose();
    _timer?.cancel();
    window.onBeginFrame = null;
    _animationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Text('Version $version');
  }
}
结论

在Flutter开发中,需要注意避免出现“颤振”的现象,而package_info的版本号请求过程中容易导致颤振,通过使用已介绍的两种方法中的一个或两个来解决这个问题,可以避免这种现象,提高Flutter应用程序的性能和交互体验。