一、页面功能总览 & 核心定位

1.1 页面名称与核心功能

本页面文件:repository_page.dart,页面标题「我的收藏」。由上一篇拓展而来,承载两大核心功能:✅ 收藏仓库管理:展示本地收藏的所有 AtomGit/GitCode 仓库列表、支持下拉刷新、左滑取消收藏、二次确认删除✅ 关注用户管理:展示本地关注的所有用户列表、支持下拉刷新、左滑取消关注、二次确认删除

1.2 核心技术栈(本页面用到的所有技术)

  1. Flutter 基础:StatefulWidget+TabBar/TabBarView 实现双 Tab 页面切换、ListView.builder实现长列表渲染
  2. 第三方插件:pull_to_refresh 实现下拉刷新功能
  3. 核心本地存储:鸿蒙适配版 shared_preferences(通过PersistenceStorage工具类封装调用)
  4. 网络请求:通过GitCodeApiClient调用 AtomGit/GitCode 的开放 API,获取仓库 / 用户的完整详情数据
  5. 交互增强:侧滑删除Dismissible、弹窗确认AlertDialog、加载状态CircularProgressIndicator

数据获取过程

用户打开RepositoryPage
      ↓
  加载动画显示
      ↓
  并行执行:
  ├─ 从SharedPreferences获取收藏仓库名列表
  ├─ 从SharedPreferences获取关注用户名列表
      ↓
  对每个仓库名:
  ├─ 通过搜索API获取仓库详情
  ├─ 添加到显示列表
      ↓
  对每个用户名:
  ├─ 通过用户详情API获取用户信息
  ├─ 添加到显示列表
      ↓
  更新UI显示结果
      ↓
  用户可以:
  ├─ 下拉刷新重新加载
  ├─ 左滑删除取消收藏/关注
  ├─ 点击项目查看详情

二、核心流程

✅ 流程一:页面初始化 & 首次加载所有数据

✅ 流程二:收藏仓库加载 & 数据渲染

三、代码解析

3.1 页面基础结构 & 全局变量定义

class RepositoryPage extends StatefulWidget {
  const RepositoryPage({super.key});
  @override
  State<RepositoryPage> createState() => _RepositoryPageState();
}

class _RepositoryPageState extends State<RepositoryPage> with SingleTickerProviderStateMixin {
  // 下拉刷新控制器
  final RefreshController _refreshController = RefreshController();
  // 网络请求实例
  final GitCodeApiClient _apiClient = GitCodeApiClient();
  // Tab切换控制器(2个Tab:收藏仓库/关注用户)
  late TabController _tabController;
  
  // 核心状态变量 - 页面所有数据的载体
  List<GitCodeRepository> _starredRepos = []; // 收藏仓库列表
  List<GitCodeUser> _followedUsers = [];      // 关注用户列表
  bool _isLoading = true;                     // 页面整体加载状态
  bool _loadingRepos = false;                 // 仓库列表单独加载状态
  bool _loadingUsers = false;                 // 用户列表单独加载状态
  String? _errorMessage;                      // 全局错误信息
}

3.2 核心数据加载方法(所有数据加载的入口)

✔ 加载全部数据 _loadAllData() 【核心主方法】
Future<void> _loadAllData() async {
  setState(() {
    _isLoading = true;
    _errorMessage = null;
  });

  try {
    // 并发加载:同时加载收藏仓库和关注用户,提升加载效率
    await Future.wait([
      _loadStarredRepositories(refresh: true),
      _loadFollowedUsers(refresh: true),
    ]);
  } catch (e) {
    setState(() {
      _errorMessage = '加载失败: ${e.toString()}';
    });
  } finally {
    setState(() {
      _isLoading = false; // 无论成功失败,最终都关闭加载状态
    });
  }
}

3.3 收藏仓库相关核心方法

✔ 加载收藏仓库列表 _loadStarredRepositories({bool refresh = false})
Future<void> _loadStarredRepositories({bool refresh = false}) async {
  if (_loadingRepos && !refresh) return; // 防重复加载:正在加载且不是刷新,直接返回
  
  setState(() {
    _loadingRepos = true;
    if (refresh) {
      _starredRepos.clear(); // 刷新时清空旧数据,保证数据最新
    }
  });

  try {
    // 第一步:从本地存储中获取【收藏的仓库全名列表】 - 核心!!!
    final repoFullNames = await PersistenceStorage.getStarredRepositories();
    
    if (repoFullNames.isEmpty) { // 无收藏仓库,直接关闭加载状态
      setState(() => _loadingRepos = false);
      return;
    }

    // 第二步:分批并发请求,避免一次性请求过多导致接口报错
    final List<GitCodeRepository> loadedRepos = [];
    const concurrentLimit = 3; // 每次并发请求3个仓库,可控并发量
    for (var i = 0; i < repoFullNames.length; i += concurrentLimit) {
      final batch = repoFullNames.sublist(i, i + concurrentLimit > repoFullNames.length ? repoFullNames.length : i + concurrentLimit);
      // 并发请求当前批次的仓库详情
      final batchResults = await Future.wait(batch.map((fullName) => _fetchRepositoryByFullName(fullName)));
      // 过滤空数据+去重,添加到临时列表
      for (final result in batchResults) {
        if (result != null && !loadedRepos.any((repo) => repo.fullName == result.fullName)) {
          loadedRepos.add(result);
        }
      }
    }

    // 第三步:更新页面数据,刷新UI
    setState(() {
      if (refresh) {
        _starredRepos = loadedRepos; // 刷新:直接替换列表
      } else {
        // 加载更多:追加数据并去重
        for (final repo in loadedRepos) {
          if (!_starredRepos.any((existing) => existing.fullName == repo.fullName)) {
            _starredRepos.add(repo);
          }
        }
      }
      _loadingRepos = false;
    });
  } catch (e) {
    print('加载收藏仓库失败: $e');
    setState(() {
      _errorMessage = '加载收藏仓库失败: ${e.toString()}';
      _loadingRepos = false;
    });
  }
}
✔ 取消收藏仓库 _unstarRepository(GitCodeRepository repository)
Future<void> _unstarRepository(GitCodeRepository repository) async {
  try {
    // 第一步:调用本地存储工具类,删除该仓库的收藏记录
    await PersistenceStorage.unstarRepository(repository.fullName);
    // 第二步:页面中移除该仓库,刷新UI
    setState(() {
      _starredRepos.removeWhere((repo) => repo.fullName == repository.fullName);
    });
    // 第三步:吐司提示操作成功
    _showSnackBar('已取消收藏 ${repository.fullName}');
  } catch (e) {
    _showSnackBar('取消收藏失败: ${e.toString()}', isError: true);
  }
}

用户关注与收藏仓库用法相似,这里不再过多赘述

3.4 shared_preferences 核心方法

// 收藏仓库相关
await PersistenceStorage.getStarredRepositories(); // 获取收藏的仓库全名列表
await PersistenceStorage.unstarRepository(fullName); // 取消收藏:删除仓库全名

// 关注用户相关
await PersistenceStorage.getFollowedUsers(); // 获取关注的用户名列表
await PersistenceStorage.unfollowUser(username); // 取消关注:删除用户名

补充:收藏仓库和关注用户的「添加」操作,是在仓库详情页 / 用户详情页调用的,对应方法是:PersistenceStorage.starRepository(fullName)PersistenceStorage.followUser(username),添加后的数据会实时同步到本页面。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐