📅  最后修改于: 2023-12-03 14:58:48.147000             🧑  作者: Mango
当程序员使用Flutter开发时,偶尔会遇到警告"颤振 package_info 没有获得内部版本号"。这篇文章将为您解释何为"颤振",以及该警告的原因和解决方法。
颤振(jitter)是指时间上的不规则抖动。在Flutter中,当某些widget的属性值改变后,如果它们不仅仅改变了呈现的外观,还改变了布局大小和位置,就会导致其它widget出现颤振。颤振可以使布局看起来比较不稳定,影响用户体验。
Flutter的package_info
库是用来获取应用程序信息的库。当某些widget使用了该库的信息,并且在每次build时,package_info版本号都被请求了两次(一次android版本号和一次ios版本号)时,就会出现上述警告。
虽然该警告不会导致应用程序崩溃或错误,但它表明了Flutter Engine更新的一个潜在风险,因此应该尽快解决。
一种解决方法是使用FutureBuilder
或ValueListenableBuilder
来请求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
库中的FrameTiming
和Vsync
类。以下是一个使用该方法的示例:
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应用程序的性能和交互体验。