You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中能否获取多个RSS Feed?求实现方案

多RSS链接接入实现方案

完全可以实现多RSS链接接入功能,以下是针对你现有代码的修改方案:

核心修改点

  • 将单个RSS链接改为URI列表,支持添加多个源
  • 批量加载所有RSS源,合并所有条目到统一列表
  • 适配UI渲染逻辑,基于合并后的条目列表展示内容

修改后的完整代码

import 'package:webfeed/webfeed.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';

class Feed extends StatefulWidget {
  const Feed({Key? key}) : super(key: key);
  final String title = 'Últimas atualizações';

  @override
  State<Feed> createState() => _FeedState();
}

class _FeedState extends State<Feed> {
  // 定义多个RSS链接列表,可继续添加更多源
  final List<Uri> feedUrls = [
    Uri(scheme: 'https', host: 'rss.tecmundo.com.br', path: 'feed'),
    Uri.parse('https://nasa.gov/rss/dyn/lg_image_of_the_day.rss'),
  ];
  List<RssItem> _allFeedItems = [];
  static const String placeholderImg = 'assets/images/noImage.jpg';
  
  late GlobalKey<RefreshIndicatorState> _refreshKey;

  @override
  void initState() {
    super.initState();
    _refreshKey = GlobalKey<RefreshIndicatorState>();
    load();
  }

  // 加载单个RSS源
  Future<RssFeed?> loadSingleFeed(Uri url) async {
    try {
      final client = http.Client();
      final response = await client.get(url);
      return RssFeed.parse(response.body);
    } catch (e) {
      debugPrint('加载RSS失败: $e');
    }
    return null;
  }

  // 批量加载所有RSS源并合并条目
  load() async {
    List<RssItem> tempItems = [];
    
    // 遍历所有RSS链接,逐个加载
    for (var url in feedUrls) {
      final feed = await loadSingleFeed(url);
      if (feed?.items != null) {
        tempItems.addAll(feed!.items!);
      }
    }

    // 按发布时间倒序排序(可选)
    tempItems.sort((a, b) => b.pubDate?.compareTo(a.pubDate ?? DateTime.now()) ?? 0);

    setState(() {
      _allFeedItems = tempItems;
    });

    // 所有源都加载失败时提示
    if (_allFeedItems.isEmpty) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text('加载失败'),
            content: const Text('所有RSS源均无法加载,请稍后重试'),
            actions: [
              TextButton(
                child: const Text('确定'),
                onPressed: () => Navigator.pop(context),
              ),
            ],
          );
        }
      );
    }
  }

  Future<void> openFeed(String url) async {
    final Uri uri = Uri.parse(url);
    if (!await launchUrl(uri, mode: LaunchMode.inAppWebView)) {
      debugPrint('打开链接失败');
    }
  }

  Text title(String? title) {
    return Text(
      title ?? '无标题',
      style: const TextStyle(
        fontSize: 18.0,
        fontWeight: FontWeight.w500,
      ),
      maxLines: 2,
      overflow: TextOverflow.ellipsis,
    );
  }

  Text subtitle(String? subtitle) {
    return Text(
      subtitle ?? '无作者',
      style: const TextStyle(
        fontSize: 14.0,
        fontWeight: FontWeight.w100,
      ),
      maxLines: 1,
      overflow: TextOverflow.ellipsis,
    );
  }

  Padding thumbnail(String? imageUrl) {
    return Padding(
      padding: const EdgeInsets.only(left: 15.0),
      child: imageUrl != null ? CachedNetworkImage(
        placeholder: (context, url) => Image.asset(placeholderImg),
        imageUrl: imageUrl,
        height: 50,
        width: 50,
        alignment: Alignment.center,
        fit: BoxFit.cover,
      ) : SizedBox(
        height: 50,
        width: 50,
        child: Image.asset(placeholderImg),
      ),
    );
  }

  ListView list() {
    return ListView.builder(
      itemCount: _allFeedItems.length,
      itemBuilder: (BuildContext context, int index) {
        final item = _allFeedItems[index];
        return ListTile(
          title: title(item.title),
          subtitle: subtitle(item.dc?.creator),
          leading: thumbnail(item.enclosure?.url),
          trailing: const Icon(Icons.bookmark_add_outlined),
          contentPadding: const EdgeInsets.all(5.0),
          onTap: () => openFeed(item.link ?? '')
        );
      },
    );
  }

  bool isFeedEmpty() {
    return _allFeedItems.isEmpty;
  }

  Widget body() => isFeedEmpty() ?
      const Center(child: CircularProgressIndicator()) :
      RefreshIndicator(
        child: list(),
        onRefresh: () => load(),
        key: _refreshKey,
      );
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('最新更新'),
      ),
      body: body(),
    );
  }
}

额外优化建议

  • 添加错误重试机制:对加载失败的单个RSS源可尝试重新加载
  • 增加条目去重:通过链接或标题字段过滤不同源的重复内容
  • 添加来源标签:给不同RSS源的条目添加标识,方便用户区分内容来源

内容的提问来源于stack exchange,提问作者Gustavo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 11:10:23