pusher-channels-flutter icon indicating copy to clipboard operation
pusher-channels-flutter copied to clipboard

pusher-channels-flutter method doesn't work when returning from another screen, or only works with newly app compilation

Open Jalalajlan opened this issue 3 years ago • 3 comments

Hi,

I have initialized pusher in the method, however, there was an issue when I use onEvent. I used setState to see data coming from an event from the pusher channel, the only time the screen updates the data coming from the pusher channel, is when I compiled the whole app that's all, but when I exit from this screen to another screen and comes back and I send an event to re-build the screen, setState isn't working and the same time event data is printed in the console, Therefore, this is only happens when exit and return to the same chat screen. I tried to print connectionState to check for any connection problem but says CONNECTED. any solution?

@maxthelion

Here is my code


import 'package:flutter/material.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:pms_user_app/models/chat_user.dart';
import 'package:pusher_channels_flutter/pusher_channels_flutter.dart';
import 'package:uuid/uuid.dart';

class ChatPage extends StatefulWidget {
  final ChatUser user;
  const ChatPage({Key? key, required this.user}) : super(key: key);

  @override
  State<ChatPage> createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage> {
  /////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////

  PusherChannelsFlutter pusher = PusherChannelsFlutter.getInstance();
  final String _apiKey = "";
  final String _cluster = "";
  final String _channelName = "my-channel";
  late PusherChannel channel;

  /////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////
  List<types.Message> messages = <types.Message>[];
  final _user = const types.User(id: '');

  @override
  void initState() {
    super.initState();
    initPusherChannel();
  }

  void initPusherChannel() async {
    try {
      if (pusher.connectionState != "CONNECTED") {
        await pusher.init(
          apiKey: _apiKey,
          cluster: _cluster,
          onConnectionStateChange: onConnectionStateChange,
        );
        await pusher.connect();
        await pusher.subscribe(
          channelName: _channelName,
          onEvent: onEvent,
        );
      }
    } catch (e) {
      throw Exception("failed to initialize pusher channels: ${e.toString()} ");
    }
  }

  // Future<void> pusherReConnect() async {
  //   try {
  //     await pusher.subscribe(
  //       channelName: _channelName,
  //       onEvent: onEvent,
  //     );
  //     await pusher.connect();
  //   } catch (e) {
  //     throw Exception(
  //         "failed to re-connect to pusher channels: ${e.toString()} ");
  //   }
  // }

  // Future<void> pusherDisconnect() async {
  //   try {
  //     await pusher.unsubscribe(
  //       channelName: _channelName,
  //     );
  //     await pusher.disconnect();
  //   } catch (e) {
  //     throw Exception(
  //         "failed to re-connect to pusher channels: ${e.toString()} ");
  //   }
  // }

  void onConnectionStateChange(
      dynamic currentState, dynamic previousState) async {
    // ignore: avoid_print
    print("Connection: $currentState");
  }

  void onEvent(dynamic event) {
    // ignore: avoid_print
    print(pusher.connectionState);
    // ignore: avoid_print
    print("event $event");
    final textMessage = types.TextMessage(
      author: _user,
      createdAt: DateTime.now().microsecondsSinceEpoch,
      id: const Uuid().v4(),
      text: "hello",
    );
    setState(() {
      messages.add(textMessage);
    });
  }

  void _handleSendPressed(types.PartialText message) {}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        automaticallyImplyLeading: false,
        backgroundColor: Colors.white,
        flexibleSpace: SafeArea(
          child: Row(
            children: <Widget>[
              IconButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                icon: const Icon(
                  Icons.arrow_back,
                  color: Colors.black,
                ),
              ),
              const SizedBox(
                width: 10,
              ),
              const CircleAvatar(
                backgroundImage: AssetImage("assets/icons/icon.png"),
                maxRadius: 20,
              ),
              const SizedBox(
                width: 12,
              ),
              Text(
                widget.user.name,
                style: GoogleFonts.poppins(
                    fontSize: 16, fontWeight: FontWeight.w600),
              ),
            ],
          ),
        ),
      ),
      body: Chat(
        messages: messages,
        onMessageTap: null,
        onSendPressed: _handleSendPressed,
        user: _user,
        showUserNames: true,
      ),
    );
  }
}

Jalalajlan avatar Sep 26 '22 01:09 Jalalajlan

I tested switching screens with Navigator.push() and then back again with Navigator.pop, and it received messages ok afterwards. I noticed you have a .pop but no .push in your code. How did you initially go to the other screen?

Secondly, your messages.add(textMessage); currently has a hard coded value of text: "hello", presumably because you're trying to debug this. Could you paste your original void onEvent(dynamic event)? Is there also a reason why you're using dynamic instead for PusherEvent?

benjamin-tang-pusher avatar Oct 12 '22 14:10 benjamin-tang-pusher

i have also same kind of issue, when I navigate to screen and connect with channel it works but after that when I try to connect with new channel than is not working, with same channel it work always but I have multiple channels, Any Solution?

usmanshoaibabbasi avatar Oct 14 '22 07:10 usmanshoaibabbasi

Did you initialise your Pusher instance in your second screen?

I suspect it doesn't work for in @Jalalajlan's code because he initialised Pusher in his _ChatPageState which looks like a second screen (which he re-opens to multiple times).

I've gotten it to work by initialising Pusher in my home screen, then in other screens re-obtained the original Pusher instance with PusherChannelsFlutter.getInstance();:

class SecondRoute extends StatelessWidget {
  const SecondRoute({super.key});

  void onSubscribePressed2() async {
    PusherChannelsFlutter pusher = PusherChannelsFlutter.getInstance();
    await pusher.subscribe(channelName: "private-third-channel");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Second Route'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: ListView(
            scrollDirection: Axis.vertical,
            shrinkWrap: true,
            children: <Widget>[
              ElevatedButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                child: const Text('Go back!'),
              ),
              ElevatedButton(
                onPressed: onSubscribePressed2,
                child: const Text('Subscribe to third channel'),
              ),
            ]),
      ),
    );
  }
}

Could you try the same? Our library works best as a singleton that you initialise once in the beginning and re-obtain in subsequent screens with PusherChannelsFlutter.getInstance(); without calling .init() again.

benjamin-tang-pusher avatar Oct 20 '22 16:10 benjamin-tang-pusher

I will close this issue, feel free to reopen it if you have feedback.

benjamin-tang-pusher avatar Nov 21 '22 15:11 benjamin-tang-pusher