我有一个带有RadListView组件的nativescript-vue应用程序,用于向用户显示数据。列表的每一行都包含当前项目的多个信息。当我点击一个按钮以加载并显示列表时,UI冻结(快速硬件->短;慢速硬件->长)。我发现加载/合并数据的代码部分运行时间很短,但是UI元素的nativescript内部渲染或创建是问题所在。 android控制台显示信息
I/Choreographer: Skipped 430 frames! The application may be doing too much work on its main thread.
我查看了stackoverflow和github,但是那里的问题(例如NativeScript Angular RadListView rendering extremely slowly)看起来很相似,但是解决方案不适合我。
我使用LinearListView(而不是Grid或Stagged),也许在我的真实应用程序中,我将能够简化列表中的行元素,但在我的示例应用程序中(向下看),我将使用简单的行ui设计。
为了获得更简单,更好的报告,我在{N} -Playground上创建了一个示例应用程序。该应用程序将创建10000个数组元素并将其设置为RadListView的源,其中每个元素都有一个Label,一个Switch和一个ActivityIndicator。
<RadListView ref="listView"
for="alarm in alarms"
layout="linear">
<v-template>
<StackLayout class="list-element" orientation="vertical" >
<GridLayout columns="*, auto, auto" rows="*">
<Label col="0" row="0">{{alarm.name}}</Label>
<Switch col="1" row="0" :checked="alarm.active" />
<ActivityIndicator col="2" row="0" :busy="alarm.active"/>
</GridLayout>
<Label class="list-element-divider"></Label>
</StackLayout>
</v-template>
</RadListView>
第一步,将在一个临时数组中生成10000个元素:
loadData() {
this.tmpAlarms = [];
for (let i = 0; i <= 10000; i++) {
this.tmpAlarms.push({
name: "Hase " + i,
active: i % 2 === 0,
});
}
}
使用第二个按钮将临时数组设置为源:
setData() {
this.alarms = this.tmpAlarms;
}
注意:即使示例应用程序在S9或其他高端智能手机上运行,我也使用10000个元素使问题可见。
完整的源代码可以在https://play.nativescript.org/?template=play-vue&id=Td1GWR下运行
在https://play.nativescript.org/?template=play-vue&id=5BXOFG下的版本与ObservableArray而不是普通数组的版本稍有不同。
在这两个版本中,数据处理都非常快,但是从内部函数生成的UI元素将很快被冻结。
示例:在装有Android 6.x的Nexus 7 2013上,UI冻结了将近6秒,并且没有其他应用在后台运行。
如果我在iOS设备(例如iPhone 7s)上尝试相同的应用程序,则渲染速度非常快,并且即使有10000个元素以及更多元素,UI仍可以流畅运行。
有谁知道我如何加快渲染速度?如果没有,建议我如何制作动画(例如ActivityIndicator)以向用户显示设备正在运行?目前,当我在UI上放置ActivityIndicator时,由于UI冻结,用户看不到它。
答案 0 :(得分:0)
Android和IOS呈现用户界面的方式非常不同。增加到Rad列表的特殊性上的这种差异可能会影响性能。请注意,rad列表重用list元素的实例以提高性能。在iOS和Android中,这种重用的方式不同。
有两种简单的优化可以改善ios和android中的渲染效果。
<RadListView ref="listView" for="alarm in alarms" layout="linear">
<v-template>
<GridLayout class="list-element" columns="*, auto, auto" rows="*, auto">
<Label col="0" row="0">{{alarm.name}}</Label>
<Switch col="1" row="0" :checked="alarm.active" />
<ActivityIndicator col="2" row="0" :busy="alarm.active"/>
<Label colSpan="3" row="1" class="list-element-divider"></Label>
</GridLayout>
</v-template>
</RadListView>
*,auto,auto
意味着它将不得不为列表中的每个元素重新计算。这就是IOS和Android不同的地方。IOS将仅呈现元素中所需的内容。这意味着当元素被回收时,堆栈布局和网格布局将保持不变,但是如果网格布局的内容在较低的元素中会更大,则滚动越多,IOS上的渲染可能就会出错。这确实更快,因为不需要每次都调整高度。但是如果需要更改大小可能会很糟糕。
Android倾向于回收,但是会重新渲染所有组件,因此需要重新计算每个组件。这样比较慢,但是更改尺寸更安全。
通常,设置和高度将提高应用程序的性能,因为从渲染引擎进行的推理较少,需要完成。在您的应用中的任何地方都是如此,但在弧度列表中确实很重要。