質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%

Q&A

解決済

1回答

1478閲覧

Flutterでsocket通信をしようとする画面遷移時にエラーが

shoshinshadao

総合スコア5

0グッド

0クリップ

投稿2022/12/15 05:02

前提

ここに質問の内容を詳しく書いてください。

Flutterでsocket_io_clientというパッケージを使って双方向通信を実装しています。
サーバー側にemitメソッドでデータを送ることはできたのですが、onメソッドを使うとデータを一時的に受信することはできるのですが、画面遷移してもう一度ページを開くと下記のエラーメッセージが出てしまいます。

実現したいこと

ここに実現したいことを箇条書きで書いてください。

  • ▲▲emitメソッドでサーバーにデータを送ったらサーバー側から「入室完了」という文字列を遷移後でも受け取りたい。

発生している問題・エラーメッセージ

[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: Bad state: Tried to use MatchingNotifier after `dispose` was called. Consider checking `mounted`. #0 StateNotifier._debugIsMounted.<anonymous closure> (package:state_notifier/state_notifier.dart:175:9) #1 StateNotifier._debugIsMounted (package:state_notifier/state_notifier.dart:182:6) #2 StateNotifier.state (package:state_notifier/state_notifier.dart:196:12) #3 MatchingNotifier.successJoinRoom.<anonymous closure> (package:quicha/viewModel/matching_viewmodel/matching_notifier.dart:34:17) #4 EventEmitter.emit.<anonymous closure> (package:socket_io_common/src/util/event_emitter.dart:65:14) #5 List.forEach (dart:core-patch/growable_array.dart:416:8) #6 EventEmitter.emit (package:socket_io_common/src/util/event_emitter.dart:64:37) #7 Function._apply (dart:core-patch/function_patch.dart:11:73) #8 Function.apply (dart:core-patch/function_patch.dart:34:12) #9 Socket.onevent (package:socket_io_clien<…>

該当のソースコード

クライアント側

socket_client.dart

1import 'package:socket_io_client/socket_io_client.dart' as IO; 2 3 4class SocketClient { 5 SocketClient(); 6 7 IO.Socket? socket; 8 static SocketClient? _instance; 9 10 SocketClient._internal(){ 11 socket = IO.io("http://localhost:3000/", <String, dynamic>{ 12 'transports' : ["websocket"], 13 'autoConnect' : false, 14 'forceNew' : true, 15 }); 16 17 socket!.connect(); 18 } 19 20 static SocketClient get instance { 21 _instance ??= SocketClient._internal(); 22 23 return _instance!; 24 } 25} 26 27

matching_notifier.dart

1import 'package:flutter_riverpod/flutter_riverpod.dart'; 2import 'package:quicha/model/socket_methods.dart'; 3import 'package:quicha/viewModel/matching_viewmodel/matching_state.dart'; 4 5import '../../model/socket_client.dart'; 6 7final matchingProvider = StateNotifierProvider.autoDispose<MatchingNotifier, MatchingState>( 8 ((ref) => MatchingNotifier()) 9); 10 11 12class MatchingNotifier extends StateNotifier<MatchingState> { 13 14 final _socketClient = SocketClient.instance.socket!; 15 16 MatchingNotifier() : super(const MatchingState()){ 17 } 18 19 void entryRoby() { 20 _socketClient.emit('entryRoby', { 21 'userId' : "12345", 22 }); 23 } 24 25 void getMyRoom() { 26 _socketClient.emit('getMyRoom'); 27 } 28/ 29 void successJoinRoom() { 30 _socketClient.once('successJoinRoom', (data) { 31 state = state.copyWith(successJoinRoom: data); 32 print(data); 33 }); 34 } 35 36 37} 38

matching_screen.dart

1import 'package:flutter/material.dart'; 2import 'package:flutter_hooks/flutter_hooks.dart'; 3import 'package:flutter_riverpod/flutter_riverpod.dart'; 4import 'package:hooks_riverpod/hooks_riverpod.dart'; 5import 'package:quicha/model/socket_client.dart'; 6import 'package:quicha/ui/custom_style.dart'; 7import 'package:quicha/viewModel/matching_viewmodel/matching_notifier.dart'; 8 9class MatchingScreen extends HookConsumerWidget { 10 const MatchingScreen({ 11 Key? key, 12 }) : super(key: key); 13 14 @override 15 Widget build(BuildContext context, ref, ) { 16 17 final state = ref.watch(matchingProvider); 18 final viewModel = ref.read(matchingProvider.notifier); 19 20 21 useEffect((){ 22 //ロビーにエントリーする 23 viewModel.entryRoby(); 24 viewModel.successJoinRoom(); 25 26 }); 27 28 return Scaffold( 29 appBar: AppBar( 30 title: Text("マッチング中……"), 31 backgroundColor: CustomColor.appBarTheme, 32 33 ), 34 body:Container( 35 child: Column( 36 children: [ 37 Text(state.successJoinRoom), 38 ElevatedButton(onPressed: (){ 39 viewModel.getMyRoom(); 40 }, child: Text("TEST")) 41 ], 42 ), 43 ), 44 ); 45 } 46} 47

サーバー側

const { Console } = require('console'); const express = require('express'); const http = require('http'); const app = express(); const server = http.createServer(app); var mongoose = require('mongoose'); const { Socket } = require('socket.io'); const PORT = process.env.PORT || 3000; var io = require('socket.io')(server); app.use(express.json()); var users = new Array(); var numb = 1; io.on('connection', (socket) => { console.log("connected!"); // socket.on('createRoom', async ({nickname}) => { // console.log(nickname); // socket.join("aiueo"); // io.to("aiueo").emit('message', "おいお茶"); // console.log(io.sockets.adapter.rooms.get("aiueo").size); // }); socket.on('entryRoby', ({userID}) => { //テスト var room = "room" + numb; socket.join(room); people = io.sockets.adapter.rooms.get(room).size; console.log(room); console.log(io.sockets.adapter.rooms.get(room).size); if(Number(people) >= 2) { numb++; } }); socket.on('getMyRoom',() => { console.log(socket.rooms); //クライアントのルームに通知 io.to(Array.from(socket.rooms)[1]).emit('successJoinRoom', '入室完了'); }); }); // 3000番ポートでHTTPサーバーを起動 server.listen(PORT,"0.0.0.0", () => { console.log(`listening on port ${PORT}`); });

試したこと

ここに問題に対して試したことを記載してください。

  • StateNotifierProviderのautodisposeが悪いのかと思ってautodisposeを外してみた。

補足情報(FW/ツールのバージョンなど)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

teratail初心者で要領の得ない質問をしてしまったなと、後から思いました。すいません。

dispose時にsocketインスタンスのclearListener()を走らせると、エラーが起きずうまくいきました。

破棄された後にリスナーが走っていてうまくいかなかったようです。

投稿2022/12/15 07:02

shoshinshadao

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問