Flutter アプリでのネットワーク接続状態のチェックメモ
connectivity_plusを利用
https://pub.dev/packages/connectivity_plus
7.0.0だとAndroidでエラーが出ることがあるので 6系を使うのが安全
connectivity_plus: 6.1.5
1回のネットワーク接続のチェック結果は ConnectivityResult の List で返ります。全く接続がない場合は、配列にnoneが一つだけ入ります。
このことを利用してこんなのを作成
wifiとmobileをチェック
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
// 状態を定義(シンプルに List<ConnectivityResult> を持つ形)
class NetworkState {
final List<ConnectivityResult> results;
NetworkState(this.results);
// 利便性のためのゲッター
bool get isOnline =>
results.contains(ConnectivityResult.mobile) ||
results.contains(ConnectivityResult.wifi);
bool get isOffline => results.contains(ConnectivityResult.none);
}
class NetworkCubit extends Cubit<NetworkState> {
late StreamSubscription<List<ConnectivityResult>> _subscription;
final Connectivity _connectivity = Connectivity();
NetworkCubit() : super(NetworkState([ConnectivityResult.none])) {
_init();
}
Future<void> _init() async {
// 初回の接続確認
final initialResult = await _connectivity.checkConnectivity();
emit(NetworkState(initialResult));
// 変化を監視
_subscription = _connectivity.onConnectivityChanged.listen((results) {
emit(NetworkState(results));
});
}
@override
Future<void> close() {
_subscription.cancel();
return super.close();
}
}
画面のベースに実装
BlocListener<NetworkCubit, NetworkState>(
listener: (context, state) {
if (state.isOffline) {
// ネットワークが切れた時にエラーを表示
showNetWorkErrorSnackBar(context);
}
},
child: ...
)
別の形式での実装
- よくあるChangeNotifierの例
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
abstract class NetworkState extends ChangeNotifier {
Future<void> initialize();
bool get isOnline;
bool get isOffline;
}
final class NetworkStateImpl extends ChangeNotifier implements NetworkState {
NetworkStateImpl();
late StreamSubscription<List<ConnectivityResult>> _subscription;
List<ConnectivityResult> _connectivityResult = [];
@override
Future<void> initialize() async {
_subscription = Connectivity().onConnectivityChanged.listen(
(List<ConnectivityResult> result) {
_connectivityResult = result;
notifyListeners();
},
);
_connectivityResult = await (Connectivity().checkConnectivity());
notifyListeners();
}
@override
bool get isOnline =>
_connectivityResult.contains(ConnectivityResult.mobile) == true ||
_connectivityResult.contains(ConnectivityResult.wifi) == true;
@override
bool get isOffline =>
_connectivityResult.contains(ConnectivityResult.none) == true;
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
}
こんなふうにして使う
ChangeNotifierProvider<NetworkState>(
create: (context) => NetworkStateImpl(),
),
final network = context.read<NetworkState>();
if (network.isOffline) {
// ネットワークが切れた時にエラーを表示
showNetWorkErrorSnackBar(context);
}
- riverpodでの例
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'network_activity_notifier.g.dart';
@Riverpod(keepAlive: true)
class NetworkActivityNotifier extends _$NetworkActivityNotifier {
late StreamSubscription<List<ConnectivityResult>> subscription;
@override
Future<List<ConnectivityResult>> build() async {
subscription = Connectivity().onConnectivityChanged.listen((
List<ConnectivityResult> result) {
state = AsyncValue.data(result);
});
ref.onDispose(() {
subscription.cancel();
});
return await (Connectivity().checkConnectivity());
}
bool get isOnline =>
state.value?.contains(ConnectivityResult.mobile) == true ||
state.value?.contains(ConnectivityResult.wifi) == true;
bool get isOffline => state.value?.contains(ConnectivityResult.none) == true;
}
こんなふうにして使う
ref.watch(networkActivityNotifierProvider);
if (ref.read(networkActivityNotifierProvider.notifier).isOffline) {
// ネットワークが切れた時にエラーを表示
showNetWorkErrorSnackBar(context);
}