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

Flutter+Provider出现Type 'Null' is not a subtype of type 'int'错误求助

Flutter收藏页报错:type 'Null' is not a subtype of type 'int' 解决方法

问题背景

开发Flutter应用时,实现用户点击保存文章ID并在收藏页展示的功能,但每次进入收藏页都会报错:type 'Null' is not a subtype of type 'int'。

用户点击保存文章的页面
用户点击保存文章的页面

需展示收藏文章的页面
需展示收藏文章的页面

相关代码

配置ChangeNotifier Provider的Main代码

class _MyAppState extends State<MyApp> {
  var data;
  var id;
  List<ArticleModel> allArticles = [];

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<FavoriteProvider>(
            create: (context) => FavoriteProvider(allArticles),
            builder: (contex, _) {
              return MaterialApp(
              debugShowCheckedModeBanner: false,
              /// Google Analytics
              navigatorObservers: [locator<AnalyticsService>().getAnalyticsObserve(),],
              theme: assoFacileNewsTheme,
              /// Routes
              initialRoute: "/splashScreen",
              routes: {
              /// Primary pages
              "/splashScreen":              (_) => SplashScreen(),
              "/onboardingScreens":         (_) => OnboardingScreens(),
              /// bottom navigation bar pages
              "/homepage":                  (_) => HomePage(),
              "/formazione":                (_) => FormazionePage(),
              "/favorite_articles":         (_) => FavoritePage(id: id,),
            },
         );
      },
    );
  }
}

ChangeNotifier页面代码

class FavoriteProvider extends ChangeNotifier {
  final List<ArticleModel> _allArticles = [];
  final List<int> _favoriteArticleIds = [];
  List<int> get favoriteArticleIds => _favoriteArticleIds;
  int get favoriteCount => _favoriteArticleIds.length;
  FavoriteProvider(List<ArticleModel> allArticles) {allArticles.addAll(allArticles);}
  /// Function to check if an article is favorited
  bool isFavorite(int favoriteArticleIds) {return _favoriteArticleIds.contains(favoriteArticleIds);} // was articleId

  /// Function to add or remove an article from favorites
  void toggleFavorite(int favoriteArticleIds, context) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    if (_favoriteArticleIds.contains(favoriteArticleIds)) {
      _favoriteArticleIds.remove(favoriteArticleIds);
      print("Removed $favoriteArticleIds from _favoriteArticleIds");
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(duration: Duration(seconds: 3),backgroundColor: Colors.white, content: Text("Articolo rimosso", style: TextStyle(color: Colors.black),),),);
    } else {
      _favoriteArticleIds.add(favoriteArticleIds);
      print("Saved $favoriteArticleIds to _favoriteArticleIds");
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(duration: Duration(seconds: 3),backgroundColor: Colors.white, content: Text("Articolo salvato", style: TextStyle(color: Colors.black),),),);
    }
    notifyListeners();
  }

  /// Fetch favourite articles
  Future<List<ArticleModel>> fetchFavoriteArticles() async {
    final favoriteArticles = _allArticles.where((article) => _favoriteArticleIds.contains(article.id)).toList();
    print("Favorite Articles in fetchFavoriteArticles: ${favoriteArticles.length}");
    return favoriteArticles;
  }
}

文章页面代码

class ArticlePage extends StatefulWidget {
  final int id; final String? urlImage; final String? title; final String? description; final dynamic data;
  const ArticlePage({Key? key, required widget.data, required widget.id, widget.urlImage, widget.title, widget.description}) : super(key: key);
  @override
  _ArticlePageState createState() => _ArticlePageState(data, id, urlImage, title, description);
}

class _ArticlePageState extends State<ArticlePage> {
  int id;final urlImage;final title;final description;final data;
  late FavoriteProvider favoriteArticles;
  late bool _favoriteArticlesReady;
  late bool isFavorite = false;
  _ArticlePageState(this.data, this.id, this.urlImage, this.title, this.description,);

  /// Function to save and remove articles
  void btnFunction() {
    favoriteArticles.toggleFavorite(widget.id, context);
    setState(() {
      isFavorite = !isFavorite;
    });
  }

  @override
  void initState() {
    super.initState();
    favoriteArticles = Provider.of<FavoriteProvider>(context, listen: false);
    isFavorite = favoriteArticles.isFavorite(widget.id);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Consumer<FavoriteProvider>(builder: (context, favoriteArticles, _) {
         return CustomScrollView(
          slivers: <Widget>[
            SliverAppBar(
              leading: const PreviousBtn(),
              flexibleSpace: FlexibleSpaceBar(
                centerTitle: true,
                background: CachedNetworkImage(
                  imageUrl: data["_embedded"]["wp:featuredmedia"][0]["link"],
                  fit: BoxFit.cover,
                  placeholder: (context, url) => Image.asset("assets/gif/shimmer.gif", fit: BoxFit.cover,),
                  errorWidget: (context, url, error) => Image.asset("assets/images/unloadedImage.png", width: 250, height: 250,
                  ),
                ),
              ),
              actions: [
                Visibility(child: Text(data['id'].toString()), visible: false,),
                /// Favorite icon
                Padding(
                  padding: const EdgeInsets.only(right: 10.0),
                  child: Container(
                      margin: const EdgeInsets.only(top: 12.0, bottom: 10.0,),
                      width: 35,
                      decoration: BoxDecoration(borderRadius: BorderRadius.circular(50), color: Colors.white,),
                      child:
                      IconButton(
                        icon: isFavorite
                            ? const Icon(Icons.bookmark_outlined, color: Color(0xFF0D47A1), size: 18,)
                            : const Icon(Icons.bookmark_outline_outlined, color: Color(0xFF0D47A1), size: 18,),
                        onPressed: btnFunction,
                      ),
                  ),
                ),
                /// Share article icon
                Padding(
                  padding: const EdgeInsets.only(right: 15.0),
                  child: IconButton(
                    icon: Image.asset('assets/images/share_icon.png',),
                    onPressed: () {
                      Share.share(data["link"], subject: "Leggi l'articolo di AssoFacile News $title",
                      );
                    },
                  ),
                ),
              ], floating: true, expandedHeight: 320,
            ),
            SliverList(
              delegate: SliverChildListDelegate([
                Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      const SizedBox(height: 20,),
                      /// Article title
                      Text(
                        data["title"]["rendered"].toString().replaceAll("<p>", "").replaceAll("&#8217;", "'").replaceAll("</p>", ""),
                        style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 20, fontFamily: "Raleway",),
                      ),
                      const SizedBox(height: 0),
                      /// Text content
                      HtmlWidget(
                        data['content']['rendered'].toString()
                            .replaceAll("<p>", "")
                            .replaceAll("&#8217;", "'")
                            .replaceAll("<img>", "")
                            .replaceAll("<div>", "<div>").replaceAll("</div>", "</div>")
                            .replaceAll("</p>", ""),
                      ),
                      const SizedBox(height: 20),
                    ],
                  ),
                ),
              ],
              ),
            ),
          ],
         );
        }
      ),
    );
  }
}

收藏页面代码

class FavoritePage extends StatefulWidget {
  final int id; final data;
  const FavoritePage({Key? key, widget.data, required widget.id}) : super(key: key);
  @override
  _FavoritePageState createState() => _FavoritePageState();
}

class _FavoritePageState extends State<FavoritePage> {
  String title  = "Articoli Preferiti";

  @override
  Widget build(BuildContext context) {
    print("Favourite page article id: ${widget.id}");
    final importFavourites = Provider.of<FavoriteProvider>(context, listen: false).fetchFavoriteArticles;
    return Scaffold(
      drawer: NavbarMenu(),
      appBar: CustomAppBar(leadingBtn: const DehazeIconBtn(), title: title,),
      body: FutureBuilder(
        future: importFavourites(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.hasData) {
              final favoriteArticlesData = snapshot.data as List<ArticleModel>;
              print("Favorite Articles Length: ${favoriteArticlesData.length}");
              if (favoriteArticlesData.isEmpty) {
                return const EmptyArticle();
              }
              return ListView.builder(
                itemCount: favoriteArticlesData.length,
                itemBuilder: (context, index) {
                  final article = favoriteArticlesData[index];
                  return Card(
                    margin: const EdgeInsets.all(8),
                    elevation: 5,
                    shadowColor: Colors.black26,
                    color: Colors.white,
                    child: InkWell(
                      child: ClipRRect(
                        borderRadius: BorderRadius.circular(10),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            SizedBox(
                              height: 190,
                              width: double.infinity,
                              child: Image(
                                image: AdvancedNetworkImage(
                                  article.urlImageSource ?? "", useDiskCache: true, cacheRule: const CacheRule(maxAge: Duration(days: 1)),
                                ), fit: BoxFit.cover,
                              ),
                            ),
                            Column(
                              children: [
                                Padding(
                                  padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16),
                                  child: Row(
                                    children: [
                                      Expanded(
                                        child: Text(
                                          article.title?.replaceAll("&#8217;", "'").replaceAll("<p>", "").replaceAll("</p>", "") ?? "",
                                          style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, fontFamily: "Raleway",),
                                          overflow: TextOverflow.ellipsis,
                                          maxLines: 2,
                                        ),
                                      ),
                                    ],
                                  ),
                                )
                              ],
                            ),
                          ],
                        ),
                      ),
                      onTap: () {
                        final id = article.id;
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => ArticlePage(data: article, id: id),
                          ),
                        );
                      },
                    ),
                  );
                },
              );
            } else {
              return const EmptyArticle();
            }
          } else {
            return const CircularProgressIndicator();
          }
        },
      ),
    );
  }
}

问题根源与修复方案

1. 路由传参的空值问题

_MyAppState中id变量未初始化,默认是null,但FavoritePage要求传入非空的int类型id,进入收藏页时直接触发类型转换错误。

修复:
收藏页不需要接收单个文章ID,它从FavoriteProvider获取所有收藏ID列表,因此删除不必要的参数:

  • 修改FavoritePage定义:
class FavoritePage extends StatefulWidget {
  const FavoritePage({Key? key}) : super(key: key);
  @override
  _FavoritePageState createState() => _FavoritePageState();
}
  • 修改路由配置:
"/favorite_articles": (_) => FavoritePage(),

2. FavoriteProvider构造函数逻辑错误

构造函数中allArticles.addAll(allArticles);是将参数列表添加到自身,导致_allArticles始终为空,后续筛选收藏文章失效。

修复:
将参数列表添加到类内部的_allArticles:

FavoriteProvider(List<ArticleModel> allArticles) {
  _allArticles.addAll(allArticles);
}

3. 收藏状态同步问题

ArticlePage手动维护isFavorite状态,易与FavoriteProvider状态不同步。

修复:
通过Consumer监听FavoriteProvider变化,自动更新图标状态:

// 替换ArticlePage中的IconButton部分
IconButton(
  icon: favoriteArticles.isFavorite(widget.id)
      ? const Icon(Icons.bookmark_outlined, color: Color(0xFF0D47A1), size: 18,)
      : const Icon(Icons.bookmark_outline_outlined, color: Color(0xFF0D47A1), size: 18,),
  onPressed: () => favoriteArticles.toggleFavorite(widget.id, context),
),

同时删除_ArticlePageState中的isFavorite变量和btnFunction。

4. SharedPreferences未持久化数据

当前代码调用了SharedPreferences但未实际保存/读取收藏ID,重启应用后数据丢失。

修复:
在FavoriteProvider中添加本地存储逻辑:

class FavoriteProvider extends ChangeNotifier {
  final List<ArticleModel> _allArticles = [];
  final List<int> _favoriteArticleIds = [];
  List<int> get favoriteArticleIds => _favoriteArticleIds;
  int get favoriteCount => _favoriteArticleIds.length;

  FavoriteProvider(List<ArticleModel> allArticles) {
    _allArticles.addAll(allArticles);
    _loadFavorites();
  }

  Future<void> _loadFavorites() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<String>? savedIds = prefs.getStringList('favorite_article_ids');
    if (savedIds != null) {
      _favoriteArticleIds.addAll(savedIds.map((id) => int.parse(id)));
      notifyListeners();
    }
  }

  Future<void> _saveFavorites() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<String> ids = _favoriteArticleIds.map((id) => id.toString()).toList();
    await prefs.setStringList('favorite_article_ids', ids);
  }

  bool isFavorite(int articleId) {
    return _favoriteArticleIds.contains(articleId);
  }

  void toggleFavorite(int articleId, context) async {
    if (_favoriteArticleIds.contains(articleId)) {
      _favoriteArticleIds.remove(articleId);
      print("Removed $articleId from _favoriteArticleIds");
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(duration: Duration(seconds: 3),backgroundColor: Colors.white, content: Text("Articolo rimosso", style: TextStyle(color: Colors.black),),),);
    } else {
      _favoriteArticleIds.add(articleId);
      print("Saved $articleId to _favoriteArticleIds");
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(duration: Duration(seconds: 3),backgroundColor: Colors.white, content: Text("Articolo salvato", style: TextStyle(color: Colors.black),),),);
    }
    await _saveFavorites();
    notifyListeners();
  }

  Future<List<ArticleModel>> fetchFavoriteArticles() async {
    final favoriteArticles = _allArticles.where((article) => _favoriteArticleIds.contains(article.id)).toList();
    print("Favorite Articles in fetchFavoriteArticles: ${favoriteArticles.length}");
    return favoriteArticles;
  }
}

内容的提问来源于stack exchange,提问作者Pimpi Rimpà

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 21:32:02