【问题标题】:Null check operator used on a null value - BloC with Null-Saftey用于空值的空值检查运算符 - 具有空值安全的 BloC
【发布时间】:2021-09-28 10:37:48
【问题描述】:

我试图理解为什么 topRatedpopular 总是得到空值,尽管结果在控制台中打印了它的值 我正在使用 电影数据库 API

import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:g_movies/models/movies_model.dart';
import 'package:g_movies/shared/cubit/cubit.dart';
import 'package:g_movies/shared/cubit/states.dart';
import 'package:g_movies/shared/styles/colors.dart';
import 'package:google_fonts/google_fonts.dart';

class MoviesLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (BuildContext context) {
        return MoviesCubit()
          ..getTopRatedData()
          ..getPopularData();
      },
      child: BlocConsumer<MoviesCubit, MoviesStates>(
        listener: (context, state) {},
        builder: (context, state) {
          return Scaffold(
            appBar: AppBar(
              title: Text(
                'GMovies',
                style: GoogleFonts.oswald(
                  fontWeight: FontWeight.bold,
                  fontSize: 24,
                  color: defaultColor,
                ),
              ),
              actions: [
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: CircleAvatar(
                    radius: 20,
                    child: IconButton(
                      icon: Icon(Icons.person),
                      onPressed: () {},
                    ),
                  ),
                ),
              ],
            ),
            body: SingleChildScrollView(
              child: Padding(
                padding: const EdgeInsets.all(20.0),
                child: Column(
                  children: [
                    ExpandablePanel(
                      theme: ExpandableThemeData(
                        headerAlignment: ExpandablePanelHeaderAlignment.center,
                      ),
                      header: Row(
                        children: [
                          Text(
                            'Top Rated',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 22,
                            ),
                          ),
                          SizedBox(
                            width: 5,
                          ),
                          Text(
                            'Movies',
                            style: TextStyle(
                              fontSize: 22,
                            ),
                          ),
                        ],
                      ),
                      collapsed: SizedBox(
                        height: 2,
                      ),
                      expanded: SizedBox(
                        width: double.infinity,
                        height: 200,
                        child: ListView.separated(
                          shrinkWrap: true,
                          scrollDirection: Axis.horizontal,
                          itemBuilder: (context, index) => movieItem(
                              MoviesCubit.get(context)
                                  .topRated!
                                  .results[index]),
                          separatorBuilder: (context, index) => SizedBox(
                            width: 10,
                          ),
                          itemCount:
                              MoviesCubit.get(context).topRated!.results.length,
                        ),
                      ),
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    ExpandablePanel(
                      theme: ExpandableThemeData(
                        headerAlignment: ExpandablePanelHeaderAlignment.center,
                      ),
                      header: Row(
                        children: [
                          Text(
                            'Popular',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 22,
                            ),
                          ),
                          SizedBox(
                            width: 5,
                          ),
                          Text(
                            'Movies',
                            style: TextStyle(
                              fontSize: 22,
                            ),
                          ),
                        ],
                      ),
                      collapsed: SizedBox(
                        height: 2,
                      ),
                      expanded: SizedBox(
                        width: double.infinity,
                        height: 200,
                        child: ListView.separated(
                          shrinkWrap: true,
                          scrollDirection: Axis.horizontal,
                          itemBuilder: (context, index) => movieItem(
                              MoviesCubit.get(context).popular!.results[index]),
                          separatorBuilder: (context, index) => SizedBox(
                            width: 10,
                          ),
                          itemCount:
                              MoviesCubit.get(context).popular!.results.length,
                        ),
                      ),
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    ExpandablePanel(
                      theme: ExpandableThemeData(
                        headerAlignment: ExpandablePanelHeaderAlignment.center,
                      ),
                      header: Row(
                        children: [
                          Text(
                            'Coming',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 22,
                            ),
                          ),
                          SizedBox(
                            width: 5,
                          ),
                          Text(
                            'Soon',
                            style: TextStyle(
                              fontSize: 22,
                            ),
                          ),
                        ],
                      ),
                      collapsed: SizedBox(
                        height: 2,
                      ),
                      expanded: SizedBox(
                        width: double.infinity,
                        height: 200,
                        child: ListView.separated(
                          shrinkWrap: true,
                          scrollDirection: Axis.horizontal,
                          itemBuilder: (context, index) => movieItem(
                              MoviesCubit.get(context)
                                  .topRated!
                                  .results[index]),
                          separatorBuilder: (context, index) => SizedBox(
                            width: 10,
                          ),
                          itemCount: 10,
                        ),
                      ),
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    ExpandablePanel(
                      theme: ExpandableThemeData(
                        headerAlignment: ExpandablePanelHeaderAlignment.center,
                      ),
                      header: Row(
                        children: [
                          Text(
                            'Now',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 22,
                            ),
                          ),
                          SizedBox(
                            width: 5,
                          ),
                          Text(
                            'Playing',
                            style: TextStyle(
                              fontSize: 22,
                            ),
                          ),
                        ],
                      ),
                      collapsed: SizedBox(
                        height: 2,
                      ),
                      expanded: SizedBox(
                        width: double.infinity,
                        height: 200,
                        child: ListView.separated(
                          shrinkWrap: true,
                          scrollDirection: Axis.horizontal,
                          itemBuilder: (context, index) => movieItem(
                              MoviesCubit.get(context)
                                  .topRated!
                                  .results[index]),
                          separatorBuilder: (context, index) => SizedBox(
                            width: 10,
                          ),
                          itemCount: 10,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          );
        },
      ),
    );
  }

  Widget movieItem(Result model) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(20),
      child: Image(
        fit: BoxFit.fill,
        width: 140,
        height: 210,
        image:
            NetworkImage('http://image.tmdb.org/t/p/w500${model.posterPath}'),
      ),
    );
  }
}

还有我的肘:

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:g_movies/models/movies_model.dart';
import 'package:g_movies/shared/cubit/states.dart';
import 'package:g_movies/shared/network/end_points.dart';
import 'package:g_movies/shared/network/remote/dio_helper.dart';

class MoviesCubit extends Cubit<MoviesStates> {
  MoviesCubit() : super(InitialState());

  static MoviesCubit get(context) => BlocProvider.of(context);

  MoviesModel? topRated;

  void getTopRatedData() {
    emit(GetTopRatedLoadingState());
    DioHelper.getData(
      url: topRatedMovies,
    ).then((value) {
      topRated = MoviesModel.fromJson(value.data);
      //print(value.data.toString());
      print(topRated!.results);
      emit(GetTopRatedSuccessState());
    }).catchError((error) {
      print(error);
      emit(GetTopRatedErrorState(error.toString()));
    });
  }

  MoviesModel? popular;

  void getPopularData() async {
    emit(GetPopularLoadingState());
    DioHelper.getData(
      url: popularMovies,
    ).then((value) {
      popular = MoviesModel.fromJson(value.data);
      //print(value.data.toString());
      print(popular!.results);
      emit(GetPopularSuccessState());
    }).catchError((error) {
      print(error);
      emit(GetPopularErrorState(error.toString()));
    });
  }
}

控制台:

Performing hot restart...
Syncing files to device AOSP on IA Emulator...
Restarted application in 3,156ms.
I/flutter (12795): onCreate -- MoviesCubit
I/flutter (12795): onChange -- MoviesCubit, Change { currentState: Instance of 'InitialState', nextState: Instance of 'GetTopRatedLoadingState' }
I/flutter (12795): onChange -- MoviesCubit, Change { currentState: Instance of 'GetTopRatedLoadingState', nextState: Instance of 'GetPopularLoadingState' }

======== Exception caught by widgets library =======================================================
The following _CastError was thrown building BlocBuilder<MoviesCubit, MoviesStates>(dirty, state: _BlocBuilderBaseState<MoviesCubit, MoviesStates>#faf5b):
Null check operator used on a null value

The relevant error-causing widget was: 
  BlocBuilder<MoviesCubit, MoviesStates> file:///C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_bloc-7.0.1/lib/src/bloc_consumer.dart:131:12
When the exception was thrown, this was the stack: 
#0      MoviesLayout.build.<anonymous closure> (package:g_movies/layout/movies_layout.dart:91:64)
#1      BlocBuilder.build (package:flutter_bloc/src/bloc_builder.dart:91:57)
#2      _BlocBuilderBaseState.build (package:flutter_bloc/src/bloc_builder.dart:163:21)
#3      StatefulElement.build (package:flutter/src/widgets/framework.dart:4691:27)
#4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4574:15)
...
====================================================================================================

======== Exception caught by widgets library =======================================================
The following _CastError was thrown building BlocBuilder<MoviesCubit, MoviesStates>(dirty, state: _BlocBuilderBaseState<MoviesCubit, MoviesStates>#faf5b):
Null check operator used on a null value

The relevant error-causing widget was: 
  BlocConsumer<MoviesCubit, MoviesStates> file:///C:/Users/agala/.AndroidStudio4.0/g_movies/lib/layout/movies_layout.dart:19:14
When the exception was thrown, this was the stack: 
#0      MoviesLayout.build.<anonymous closure> (package:g_movies/layout/movies_layout.dart:91:64)
#1      BlocBuilder.build (package:flutter_bloc/src/bloc_builder.dart:91:57)
#2      _BlocBuilderBaseState.build (package:flutter_bloc/src/bloc_builder.dart:163:21)
#3      StatefulElement.build (package:flutter/src/widgets/framework.dart:4691:27)
#4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4574:15)
...
====================================================================================================
I/flutter (12795): Invalid argument(s) (input): Must not be null
I/flutter (12795): onChange -- MoviesCubit, Change { currentState: Instance of 'GetPopularLoadingState', nextState: Instance of 'GetPopularErrorState' }
I/flutter (12795): [Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result', Instance of 'Result']
I/flutter (12795): onChange -- MoviesCubit, Change { currentState: Instance of 'GetPopularErrorState', nextState: Instance of 'GetTopRatedSuccessState' }

【问题讨论】:

  • 您的 MoviesStates 是否总是具有 nun-null 值 topRated ?我没有看到你的定义类。

标签: flutter dart runtime-error bloc dart-null-safety


【解决方案1】:

当您访问 MoviesStates 的 topRated 或流行变量时,
您需要在 BlocBuilder 中检查状态状态。

我建议使用下面文章中的事件和状态。
https://blog.logrocket.com/state-management-flutter-bloc-pattern/

建议

  1. [MoviesLayout] 发送数据加载事件以获取 topRate 和热门数据
  2. [MoviesCubit]接收数据加载事件并调用api获取数据
  3. [MoviesCubit] 使用 topRate 和流行数据发出数据加载完成状态
  4. [MoviesLayout] 在 BlocBuilder 中数据加载完成状态的情况下,
    构建访问州的 topRate 和流行数据的布局。
    (如果 State 不是数据加载完成状态,则构建加载布局。)

【讨论】:

    【解决方案2】:

    BlocBuilder 中返回小部件之前,您应该检查块的不同状态以确保数据已加载并且没有发生错误:

    
    // ... other lines
    
    body: BlocConsumer<MoviesCubit, MoviesStates>(
      listener: (context, state) {},
      builder: (context, state) {
    
        // If the bloc is still in loading state
    
        if (state is GetTopRatedLoadingState ||
            state is GetPopularLoadingState) {
          return Container(child: Center(child: CircularProgressIndicator()));
        } else if (state is GetTopRatedErrorState || state is GetPopularErrorState) {
    
          // Return your error widget here with the error message
    
        }
    
        // If everything is success
    
        return Scaffold(
          appBar: AppBar(
            title: Text(
              'GMovies',
              style: GoogleFonts.oswald(
                fontWeight: FontWeight.bold,
                fontSize: 24,
                color: defaultColor,
              ),
            ),
          ),
    
          // ... other lines
    
        );
      },
    )
    

    当显示具有 2 个不同数据源的 2 个列表时,您应该使用 2 个不同的 bloc,这样当 1 个数据源发生故障时,它不会影响另一个数据源。在这种情况下,将topRatedpopular 数据拆分到不同的BlocBuilder 可以更好地避免潜在的错误。

    【讨论】:

      猜你喜欢
      • 2021-08-30
      • 2022-01-11
      • 2021-12-03
      • 2022-01-18
      • 2021-01-24
      • 2022-07-06
      • 1970-01-01
      • 2021-02-25
      • 2022-01-06
      相关资源
      最近更新 更多