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);
    }
  });
}

九、总结

本文深入讲解了投票管理系统中的统计和排序技术,主要内容包括:

  1. 选票验证算法:三层判断机制(弃权、废票、有效)
  2. 实时统计机制:动态更新统计数据
  3. 排序算法实现:Dart内置排序、自定义排序规则
  4. 状态管理模式:setState最佳实践、状态快照
  5. 数据可视化:颜色编码、进度条、排名徽章
  6. 高级功能:历史记录、数据导出、多轮投票
  7. 性能优化:减少重建、列表优化、状态优化

掌握这些技术可以让你开发出功能强大、性能优秀的投票应用。在实际项目中,还需要考虑数据安全、防作弊、并发访问等方面,确保应用的公正性和可靠性。


欢迎加入开源鸿蒙跨平台社区: 开源鸿蒙跨平台开发者社区

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐