【问题标题】:Cannot retrieve the status of the internet connection when the app is re-launched or hot restarted with internet off重新启动应用程序或在关闭互联网的情况下热重启时无法检索互联网连接的状态
【发布时间】:2021-10-08 15:16:37
【问题描述】:

我正在尝试将 BLoC 库与 Flutter 中的 connectivity_plus 插件一起使用。我已经按照 post 和 post 为该项目设置了 Internet Cubit。当应用程序在打开互联网连接的情况下启动时,代码可以正常工作。

但是,在关闭互联网连接的情况下,如果我终止应用并重新启动它或进行热重启,则会显示 CircularProgressIndicator() 而不是 Text("Internet Disconnected")。

正确打开互联网会显示Text("Internet Connected") 小部件。在此之后,如果我再次关闭互联网连接,这一次它会正确显示 Text("Internet Disconnected") 小部件。

此外,emitInternetDisconnected 不会在 try catch 块中被捕获为异常以更新应用的状态。

CircularProgressIndicator() 总是在断网的情况下显示的问题只有在应用重新启动或热重启时才会出现。我无法弄清楚我的代码中的错误。我应该怎么做才能修复我的代码?谢谢

这是internet_cubit.dart文件中的代码

import 'dart:async';
import 'dart:io';

import 'package:bloc/bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';

import 'internet_enum.dart';

part 'internet_state.dart';

class InternetCubit extends Cubit<InternetState> {
  final Connectivity? connectivity;
  StreamSubscription? connectivityStreamSubscription;

  InternetCubit({required this.connectivity}) : super(InternetLoading()) {
    monitorInternetConnection();
  }

  void monitorInternetConnection() async {
    connectivityStreamSubscription =
        connectivity!.onConnectivityChanged.listen((connectivityResult) async {
      try {
        final result = await InternetAddress.lookup("example.com");
        if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
          if (connectivityResult == ConnectivityResult.wifi) {
            emitInternetConnected(ConnectionType.WiFi);
          } else if (connectivityResult == ConnectivityResult.mobile) {
            emitInternetConnected(ConnectionType.Mobile);
          } else if (connectivityResult == ConnectivityResult.none) {
            emitInternetDisconnected();
          }
        }
      } on SocketException catch (_) {
        emitInternetDisconnected();
      }
    });
  }

  void emitInternetConnected(ConnectionType _connectionType) =>
      emit(InternetConnected(connectionType: _connectionType));

  void emitInternetDisconnected() => emit(InternetDisconnected());

  @override
  Future<void> close() async {
    connectivityStreamSubscription!.cancel();
    return super.close();
  }
}

这是internet_state.dart文件中的代码

part of 'internet_cubit.dart';

abstract class InternetState {}

class InternetLoading extends InternetState {}

class InternetConnected extends InternetState {
  final ConnectionType? connectionType;

  InternetConnected({required this.connectionType});
}

class InternetDisconnected extends InternetState {}

这是我的main.dart 文件中的代码

import 'package:flutter/material.dart';

import 'package:flutter_bloc/flutter_bloc.dart';

import 'package:connectivity_plus/connectivity_plus.dart';

import 'internet_cubit.dart';

void main() {
  runApp(
    BlocProvider<InternetCubit>(
      create: (_) => InternetCubit(connectivity: Connectivity()),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter BLoC Demo',
      home: SafeArea(
        child: Scaffold(
          appBar: AppBar(
            title: Text("Flutter BLoC Demo"),
            centerTitle: true,
            backgroundColor: Colors.blue[900],
          ),
          body: Center(
            child: Builder(
              builder: (context) {
                return MaterialButton(
                    onPressed: () {
                      Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenOne()));
                    },
                    color: Colors.black,
                    textColor: Colors.white,
                    child: Text("Screen 1"));
              },
            ),
          ),
        ),
      ),
    );
  }
}

class ScreenOne extends StatelessWidget {
  const ScreenOne({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Text("Flutter BLoC Demo"),
          centerTitle: true,
          backgroundColor: Colors.blue[900],
        ),
        body: Center(
          child: BlocBuilder<InternetCubit, InternetState>(
            builder: (_, state) {
              if (state is InternetDisconnected) {
                return Text("Internet disconnected");
              } else if (state is InternetConnected) {
                return Text("Internet connected");
              }
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

【问题讨论】:

    标签: flutter bloc


    【解决方案1】:

    我怀疑问题出在网络层的 Internet 连接上,所以我尝试了不同的方法。我将在此处发布我的解决方案,以便对遇到类似问题的人有用。

    首先,我修改了internet_cubit.dart 和internet_state.dart 文件,如下所示:

    import 'dart:async';
    
    import 'package:bloc/bloc.dart';
    import 'package:connectivity_plus/connectivity_plus.dart';
    
    import 'internet_enum.dart';
    
    part 'internet_state.dart';
    
    class InternetCubit extends Cubit<InternetConnectionTypeState> {
      final Connectivity? connectivity;
      // ignore: cancel_subscriptions
      StreamSubscription? internetConnectionTypeStreamSubscription;
    
      InternetCubit({required this.connectivity}) : super(InternetConnectionTypeLoading()) {
        monitorConnectionType();
      }
    
      void monitorConnectionType() async {
        internetConnectionTypeStreamSubscription =
            connectivity!.onConnectivityChanged.listen((connectivityResult) async {
          if (connectivityResult == ConnectivityResult.wifi) {
            emitConnectionType(ConnectionType.WiFi);
          } else if (connectivityResult == ConnectivityResult.mobile) {
            emitConnectionType(ConnectionType.Mobile);
          }
        });
      }
    
      void emitConnectionType(ConnectionType _connectionType) =>
          emit(InternetConnectionType(connectionType: _connectionType));
    
      @override
      Future<void> close() async {
        internetConnectionTypeStreamSubscription!.cancel();
        return super.close();
      }
    }
    
    part of 'internet_cubit.dart';
    
    abstract class InternetConnectionTypeState {}
    
    class InternetConnectionTypeLoading extends InternetConnectionTypeState {}
    
    class InternetConnectionType extends InternetConnectionTypeState {
      final ConnectionType? connectionType;
    
      InternetConnectionType({required this.connectionType});
    }
    

    这是internet_enum.dart 文件:

    enum ConnectionType {
      WiFi, Mobile
    }
    

    接下来,我导入了internet_connection_checker 包。我创建了一个名为ConnectionCheckerCubit 的新cubit class。按照上述代码作为指导和internet_connection_checkerpackage 的文档,这里是connection_cubit.dart 和connection_state.dart 文件的代码。

    import 'dart:async';
    
    import 'package:bloc/bloc.dart';
    import 'package:internet_connection_checker/internet_connection_checker.dart';
    
    part 'connection_state.dart';
    
    class ConnectionCheckerCubit extends Cubit<ConnectionCheckerState> {
      final InternetConnectionChecker? internetConnectionChecker;
    
      ConnectionCheckerCubit({required this.internetConnectionChecker}) : super(InternetConnectionLoading()) {
        monitorInternetConnection();
      }
    
      // ignore: cancel_subscriptions
      StreamSubscription? internetConnectionStreamSubscription;
    
      void monitorInternetConnection() async {
        internetConnectionStreamSubscription = InternetConnectionChecker().onStatusChange.listen((status) {
          switch (status) {
            case InternetConnectionStatus.connected:
              emitInternetConnectionConnected(InternetConnectionStatus.connected);
              break;
            case InternetConnectionStatus.disconnected:
              emitInternetConnectionDisconnected();
              break;
          }
        });
      }
    
      void emitInternetConnectionConnected(InternetConnectionStatus _internetConnectionStatus) =>
          emit(InternetConnectionConnected(internetConnectionStatus: _internetConnectionStatus));
    
      void emitInternetConnectionDisconnected() => emit(InternetConnectionDisconnected());
    
      @override
      Future<void> close() async {
        internetConnectionStreamSubscription!.cancel();
        return super.close();
      }
    }
    
    part of 'connection_cubit.dart';
    
    abstract class ConnectionCheckerState {}
    
    class InternetConnectionLoading extends ConnectionCheckerState {}
    
    class InternetConnectionConnected extends ConnectionCheckerState {
      final InternetConnectionStatus? internetConnectionStatus;
    
      InternetConnectionConnected({required this.internetConnectionStatus});
    }
    
    class InternetConnectionDisconnected extends ConnectionCheckerState {}
    

    在main.dart 文件中,我使用main() 函数中的MultiBlocProvider 作为runApp 的包装器。在ScreenOne 小部件中,我为InternetCubit 使用了BlocBuilder 小部件,并使用context.watch&lt;ConnectionCheckerCubit&gt;().state 来监控ConnectionCheckerCubit 的状态。此外,我还添加了一个 AppBlocObserver 类用于调试目的。这是main.dart 文件的代码:

    import 'dart:developer';
    
    import 'package:internet_connection_checker/internet_connection_checker.dart';
    import 'package:flutter/material.dart';
    
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:bloc/bloc.dart';
    
    import 'package:connectivity_plus/connectivity_plus.dart';
    import 'package:flutter_bloc_api/internet_enum.dart';
    import 'connection_cubit.dart';
    
    import 'internet_cubit.dart';
    
    void main() {
    
      Bloc.observer = AppBlocObserver();
      runApp(
        MultiBlocProvider(
          providers: [
            BlocProvider<ConnectionCheckerCubit>(
              create: (_) => ConnectionCheckerCubit(internetConnectionChecker: InternetConnectionChecker()),
            ),
            BlocProvider<InternetCubit>(
              create: (_) => InternetCubit(connectivity: Connectivity()),
            ),
          ],
          child: MyApp(),
        ),
      );
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter BLoC Demo',
          home: SafeArea(
            child: Scaffold(
              appBar: AppBar(
                title: Text("Flutter BLoC Demo"),
                centerTitle: true,
                backgroundColor: Colors.blue[900],
              ),
              body: Center(
                child: Builder(
                  builder: (context) {
                    return MaterialButton(
                        onPressed: () {
                          Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenOne()));
                        },
                        color: Colors.black,
                        textColor: Colors.white,
                        child: Text("Screen 1"));
                  },
                ),
              ),
            ),
          ),
        );
      }
    }
    
    class ScreenOne extends StatelessWidget {
      const ScreenOne({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Scaffold(
            appBar: AppBar(
              title: Text("Flutter BLoC Demo"),
              centerTitle: true,
              backgroundColor: Colors.blue[900],
            ),
            body: Center(
              child: Builder(
                builder: (context) {
                  final connectionState = context.watch<ConnectionCheckerCubit>().state;
                  final internetTypeState = context.watch<InternetCubit>().state;
                  if (connectionState is InternetConnectionDisconnected)
                    return Text("Internet Disconnected");
                  else if (connectionState is InternetConnectionConnected){
                    if (internetTypeState is InternetConnectionType && internetTypeState.connectionType == ConnectionType.WiFi)
                      return Text("WiFi");
                    else
                      return Text("Mobile");
                  }
                  return CircularProgressIndicator();
                }
              )
            ),
          ),
        );
      }
    }
    
    class AppBlocObserver extends BlocObserver {
      @override
      void onChange(BlocBase bloc, Change change) {
        super.onChange(bloc, change);
        log('onChange: ${bloc.runtimeType}, ${bloc.state} \nCurrent state: ${change.currentState}\nNext state: ${change.nextState}');
      }
    
      @override
      void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
        log('onError(${bloc.runtimeType}, ${bloc.state}, $error, $stackTrace)');
        super.onError(bloc, error, stackTrace);
      }
    
      @override
      void onEvent(Bloc bloc, Object? event) {
        log('onEvent(${bloc.state}, ${bloc.runtimeType}, $event)');
        super.onEvent(bloc, event);
      }
    
      @override
      void onTransition(Bloc bloc, Transition transition) {
        log('onTransition(${bloc.state}, ${bloc.runtimeType}, ${transition.currentState}, ${transition.nextState})');
        super.onTransition(bloc, transition);
      }
    
      @override
      void onCreate(BlocBase bloc) {
        log('onCreate(${bloc.state}, ${bloc.runtimeType})');
        super.onCreate(bloc);
      }
    
      @override
      void onClose(BlocBase bloc) {
        log('onTransition(${bloc.state}, ${bloc.runtimeType})');
        super.onClose(bloc);
      }
    }
    

    这里是 Github link 了解更多信息。

    【讨论】:

      【解决方案2】:

      添加这个库connectivity: ^3.0.6

      在你的课堂上试试这个代码:-

      _startNetworkTesting(BuildContext context) async {
          
          var result = await (Connectivity().checkConnectivity());
          if (result == ConnectivityResult.none) {
            setState(() {
             //perform your action
            });
          } else if (result == ConnectivityResult.mobile) {
            setState(() {
             //perform your action
            });
          } else if (result == ConnectivityResult.wifi) {
            setState(() {
              //perform your action
            });
          }
        }
      

      【讨论】:

      • 连接插件将来可能会被弃用。根据文档,建议使用connectivity_plus 插件。当函数中不使用 BuildContext 作为参数时,它的目的是什么?我更喜欢使用 BLoC 作为状态管理解决方案,而不是 setState() 来检查应用程序中的互联网连接
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-14
      • 2022-11-03
      • 1970-01-01
      • 2015-03-10
      • 1970-01-01
      相关资源
      最近更新 更多