Flutter for OpenHarmony 进阶:数据统计与排序算法深度解析
本文深入解析Flutter在鸿蒙平台上构建投票管理系统的核心算法与实现技术。主要内容包括:1) 选票验证算法,详细讲解弃权票、废票和有效票的三层判断逻辑;2) 实时统计机制,展示如何设计数据结构并实现票数实时更新;3) 排序算法实现,分析Dart内置排序方法及多条件排序规则;4) 状态管理模式,介绍StatefulWidget+setState的基础方案。通过本文,开发者可掌握投票系统核心功能的技
·
Flutter for OpenHarmony 进阶:数据统计与排序算法深度解析
文章目录
摘要

数据统计与排序是投票管理系统的核心功能。本文深入讲解投票系统中的统计机制和排序算法,详细分析选票验证逻辑、实时数据更新、票数排序实现等高级技术点。通过本文学习,读者将掌握Flutter在鸿蒙平台上的数据处理和算法实现技巧,了解如何构建高效、准确的统计系统。
一、投票系统核心算法概述
1.1 核心算法类型
投票系统涉及以下核心算法:
- 验证算法:判断选票有效性
- 统计算法:实时更新票数
- 排序算法:按票数排序候选人
- 状态管理:管理应用状态变化
1.2 数据流分析

二、选票验证算法
2.1 验证规则定义
| 规则 | 条件 | 结果 |
|---|---|---|
| 弃权票 | 选中0人 | 弃权计数+1 |
| 有效票 | 选中1-3人 | 各候选人票数+1 |
| 废票 | 选中>3人 | 废票计数+1 |
2.2 验证算法实现
void _submitVote() {
// 第一层判断:弃权检测
if (_selectedCandidates.isEmpty) {
_handleAbstainedVote();
return;
}
// 第二层判断:废票检测
if (_selectedCandidates.length > 3) {
_handleInvalidVote();
return;
}
// 第三层:有效票处理
_handleValidVote();
}
2.3 弃权票处理

void _handleAbstainedVote() {
setState(() {
_abstainedVotes++; // 弃权计数加1
_totalVotes++; // 总票数加1
_selectedCandidates.clear(); // 清空选择
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('弃权票已记录')),
);
}
处理要点
- 弃权不计入任何候选人
- 总票数仍需增加
- 清空选择状态
2.4 废票处理
void _handleInvalidVote() {
setState(() {
_invalidVotes++; // 废票计数加1
_totalVotes++; // 总票数加1
_selectedCandidates.clear(); // 清空选择
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('选择超过3人,该票作废'),
backgroundColor: Colors.red, // 红色警告
),
);
}
处理要点
- 废票不计入任何候选人
- 使用红色提示用户
- 清空选择状态
2.5 有效票处理
void _handleValidVote() {
setState(() {
// 为每个选中的候选人增加票数
for (var candidate in _candidates) {
if (_selectedCandidates.contains(candidate.name)) {
candidate.votes++;
}
}
_totalVotes++;
_selectedCandidates.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('投票成功')),
);
}
处理要点
- 遍历所有候选人
- 为选中的候选人增加票数
- 更新总票数
三、实时统计机制
3.1 统计数据结构
class _VotingSystemPageState extends State<VotingSystemPage> {
int _totalVotes = 0; // 总选票数
int _invalidVotes = 0; // 废票数
int _abstainedVotes = 0; // 弃权票数
// 有效票 = 总票数 - 废票 - 弃权票
}
3.2 统计更新时机
// 每次投票后更新
setState(() {
// 更新统计
_totalVotes++;
// 触发UI重新渲染
});
// 实时计算有效票数
int get _validVotes {
return _totalVotes - _invalidVotes - _abstainedVotes;
}
3.3 统计展示组件
Widget _buildStatCard(String title, String value, Color color) {
return Expanded(
child: Card(
color: color,
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
children: [
Text(
title,
style: const TextStyle(
fontSize: 12,
color: Colors.white,
),
),
const SizedBox(height: 4),
Text(
value,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
),
);
}
3.4 有效票计算
// 方式一:实时计算
_buildStatCard('有效票', '${_totalVotes - _invalidVotes - _abstainedVotes}', Colors.green)
// 方式二:使用getter
int get _validVotes => _totalVotes - _invalidVotes - _abstainedVotes;
// 方式三:单独存储(需要额外维护)
int _validVotes = 0;
setState(() {
_validVotes++;
});
推荐方式
- 小型应用:实时计算(方式一)
- 中型应用:使用getter(方式二)
- 大型应用:单独存储并维护(方式三)
四、排序算法实现

4.1 排序需求分析
按候选人得票数从高到低排序,方便查看排名。
4.2 Dart内置排序
void _sortByVotes() {
setState(() {
_candidates.sort((a, b) => b.votes.compareTo(a.votes));
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已按票数排序')),
);
}
排序原理
- 使用Dart List的sort方法
- 比较函数返回负数表示a在前
- b.votes.compareTo(a.votes)实现降序
4.3 自定义排序规则
按票数降序
_candidates.sort((a, b) => b.votes.compareTo(a.votes));
按票数升序
_candidates.sort((a, b) => a.votes.compareTo(b.votes));
按姓名排序
_candidates.sort((a, b) => a.name.compareTo(b.name));
多条件排序(票数优先,姓名其次)
_candidates.sort((a, b) {
// 先比较票数
int voteCompare = b.votes.compareTo(a.votes);
if (voteCompare != 0) {
return voteCompare;
}
// 票数相同,按姓名排序
return a.name.compareTo(b.name);
});
4.4 稳定排序
Dart的sort是稳定排序,相同元素的相对顺序保持不变:
// 排序前
[张三(5票), 李四(3票), 王五(5票)]
// 排序后(李四在后,因为原位置靠后)
[张三(5票), 王五(5票), 李四(3票)]
4.5 排序算法复杂度
Dart使用的是混合排序算法:
- 平均时间复杂度:O(n log n)
- 最坏时间复杂度:O(n log n)
- 空间复杂度:O(n)
对于小型投票系统(<100候选人),性能完全足够。
五、状态管理模式
5.1 当前状态管理方式
使用StatefulWidget + setState:
class _VotingSystemPageState extends State<VotingSystemPage> {
// 状态变量
final List<Candidate> _candidates = [];
final Set<String> _selectedCandidates = {};
int _totalVotes = 0;
// ...
// 状态更新
void _updateState() {
setState(() {
// 修改状态
});
}
}
5.2 状态更新最佳实践
批量更新
// 不推荐:多次setState
setState(() {
_totalVotes++;
});
setState(() {
_selectedCandidates.clear();
});
// 推荐:单次setState
setState(() {
_totalVotes++;
_selectedCandidates.clear();
});
条件更新
// 避免不必要的更新
void _toggleSelection(String name) {
bool wasSelected = _selectedCandidates.contains(name);
bool willBeSelected = !wasSelected;
setState(() {
if (willBeSelected) {
_selectedCandidates.add(name);
} else {
_selectedCandidates.remove(name);
}
});
}
5.3 状态快照
保存当前状态以便恢复:
Map<String, dynamic> _getStateSnapshot() {
return {
'candidates': _candidates.map((c) => {'name': c.name, 'votes': c.votes}).toList(),
'totalVotes': _totalVotes,
'invalidVotes': _invalidVotes,
'abstainedVotes': _abstainedVotes,
};
}
void _restoreState(Map<String, dynamic> snapshot) {
setState(() {
// 恢复状态
});
}
六、数据可视化
6.1 颜色编码系统
使用颜色区分不同类型的票:
// 总票数 - 蓝色(中性)
_buildStatCard('总选票', '$_totalVotes', Colors.blue)
// 有效票 - 绿色(成功)
_buildStatCard('有效票', '$_validVotes', Colors.green)
// 废票 - 红色(警告)
_buildStatCard('废票', '$_invalidVotes', Colors.red)
// 弃权 - 灰色(中立)
_buildStatCard('弃权', '$_abstainedVotes', Colors.grey)
6.2 进度条展示
使用进度条显示得票比例:
Widget _buildProgressBar(Candidate candidate, int totalVotes) {
if (totalVotes == 0) return const SizedBox.shrink();
double percentage = candidate.votes / totalVotes;
return Column(
children: [
Text('${candidate.name}: ${candidate.votes}票'),
LinearProgressIndicator(
value: percentage,
backgroundColor: Colors.grey[200],
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
),
Text('${(percentage * 100).toStringAsFixed(1)}%'),
],
);
}
6.3 排名徽章
为前三名添加特殊标识:
Widget _buildRankBadge(int index) {
if (index == 0) {
return const Icon(Icons.emoji_events, color: Colors.amber); // 金牌
} else if (index == 1) {
return const Icon(Icons.emoji_events, color: Colors.grey); // 银牌
} else if (index == 2) {
return const Icon(Icons.emoji_events, color: Colors.brown); // 铜牌
}
return null;
}
七、高级功能扩展
7.1 历史记录功能
class VoteRecord {
final DateTime timestamp;
final List<String> selectedCandidates;
final VoteType type;
enum VoteType { valid, invalid, abstained }
}
class _VotingSystemPageState extends State<VotingSystemPage> {
final List<VoteRecord> _voteHistory = [];
void _recordVote(VoteType type) {
_voteHistory.add(VoteRecord(
timestamp: DateTime.now(),
selectedCandidates: List.from(_selectedCandidates),
type: type,
));
}
void _showHistory() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('投票历史'),
content: SizedBox(
width: double.maxFinite,
child: ListView.builder(
itemCount: _voteHistory.length,
itemBuilder: (context, index) {
final record = _voteHistory[index];
return ListTile(
title: Text(record.type.toString()),
subtitle: Text(record.timestamp.toString()),
);
},
),
),
),
);
}
}
7.2 数据导出功能
Future<void> _exportResults() async {
// 生成CSV格式
final buffer = StringBuffer();
buffer.writeln('排名,候选人,得票数,得票率');
final sortedCandidates = List.from(_candidates);
sortedCandidates.sort((a, b) => b.votes.compareTo(a.votes));
for (int i = 0; i < sortedCandidates.length; i++) {
final candidate = sortedCandidates[i];
final percentage = _totalVotes > 0
? (candidate.votes / _totalVotes * 100).toStringAsFixed(2)
: '0.00';
buffer.writeln('${i + 1},${candidate.name},${candidate.votes},$percentage%');
}
// 保存文件
// ...
}
7.3 多轮投票支持
class _VotingSystemPageState extends State<VotingSystemPage> {
int _currentRound = 1;
final List<Map<String, dynamic>> _roundResults = [];
void _startNewRound() {
// 保存当前轮次结果
_roundResults.add({
'round': _currentRound,
'candidates': List.from(_candidates),
'statistics': {
'total': _totalVotes,
'invalid': _invalidVotes,
'abstained': _abstainedVotes,
},
});
// 重置状态
setState(() {
_currentRound++;
_resetStatistics();
for (var candidate in _candidates) {
candidate.votes = 0;
}
});
}
}
八、性能优化策略
8.1 减少不必要的重建
使用const构造函数:
// 不推荐
const Card(
child: Text('投票规则'),
)
// 推荐:尽可能使用const
const Card(
child: Text('投票规则'),
)
8.2 列表优化
对于大量候选人,使用ListView.builder:
// 推荐:懒加载
ListView.builder(
itemCount: _candidates.length,
itemBuilder: (context, index) {
return _buildCandidateItem(_candidates[index]);
},
)
// 不推荐:一次性构建
Column(
children: _candidates.map((c) => _buildCandidateItem(c)).toList(),
)
8.3 状态更新优化
只在必要时更新状态:
// 检查状态是否真的需要更新
void _toggleSelection(String name) {
bool alreadySelected = _selectedCandidates.contains(name);
if (alreadySelected && _selectedCandidates.length > 3) {
// 不需要更新,直接返回
return;
}
setState(() {
if (alreadySelected) {
_selectedCandidates.remove(name);
} else {
_selectedCandidates.add(name);
}
});
}
九、总结
本文深入讲解了投票管理系统中的统计和排序技术,主要内容包括:
- 选票验证算法:三层判断机制(弃权、废票、有效)
- 实时统计机制:动态更新统计数据
- 排序算法实现:Dart内置排序、自定义排序规则
- 状态管理模式:setState最佳实践、状态快照
- 数据可视化:颜色编码、进度条、排名徽章
- 高级功能:历史记录、数据导出、多轮投票
- 性能优化:减少重建、列表优化、状态优化
掌握这些技术可以让你开发出功能强大、性能优秀的投票应用。在实际项目中,还需要考虑数据安全、防作弊、并发访问等方面,确保应用的公正性和可靠性。
欢迎加入开源鸿蒙跨平台社区: 开源鸿蒙跨平台开发者社区
更多推荐



所有评论(0)