флаттер разделяет состояние между несколькими экземплярами виджета

В моем приложении flutter у меня есть виджет ConnectivityStatus, который отображает текущий статус подключения приложения к моему Raspberry Pi. В initState моего виджета я подписываюсь на таймер, чтобы проверять соединение каждые 5 секунд и соответствующим образом обновлять состояние, а затем отказаться от подписки при удалении.

Проблема в том, что когда несколько экранов используют виджет ConnectivityStatus, например, при настройке навигатора стека, у меня теперь есть две одновременные подписки, поскольку ни один из экземпляров не удален. Это вызывает появление множества избыточных, ненужных запросов.

На самом деле я хочу либо поделиться одним экземпляром виджета на нескольких экранах, либо иметь одно глобальное состояние, к которому могут обращаться несколько экземпляров.

Как я могу добиться этого или какие другие рекомендуемые решения моей проблемы?


person John Schlachtenhaufen    schedule 08.05.2020    source источник


Ответы (3)


Самый простой способ добиться этого - использовать InheritedWidget для передачи ConnectivityStatus нисходящим виджетам. https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html

Вы также можете изучить другие решения для управления состоянием, такие как Provider https://pub.dev/packages/provider или Bloc https://pub.dev/packages/flutter_bloc

person dshukertjr    schedule 08.05.2020

Я предлагаю использовать Provider и создать RPIService, который отправляет поток статуса подключения.

class RPIService {
  var RPIstatus = ValueNotifier<Status>(Status('offline'));

RPIService(){

rpi...listen((cstatus){
RPIstatus.add(Status(cstatus));

});

}}

class Status {
final String statusMessage;
 Status(this.statusMessage);
} 

main.dart

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [

       Provider<UserService>(
       create: (context) => UserService(),
       lazy: false,

       ),
        StreamProvider<Status>(
          create: (context) =>
              Provider.of<RPIService>(context, listen: false).RPIstatus,
        ),
      ],
      child: MaterialApp(
        title: 'Your app',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: YourHome(),
      ),
    );
  }
}

yourHome.dart

class YourHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<Status>(builder: (context, status, _) {
      return Scaffold(
        body: Text(status.status),
      );
    });
  }
}
person SempaiLeo    schedule 08.05.2020

Другой способ добиться этого - использовать GlobalKey, поскольку это официальный способ Flutter поделиться одним состоянием виджета в приложении.

В файле key.dart:

final GlobalKey<ConnectivityStatusState> connectivityStatusKey = GlobalKey();

Когда вы создаете свой ConnectivityStatus виджет:

ConnectivityStatus(
  key: connectivityStatusKey,
  ...
)

Где вы хотите получить доступ к состоянию ConnectivityStatus:

connectivityStatusKey.currentState.anythingPublicInThisState()

Чтобы использовать это, убедитесь, что ваш класс состояния является общедоступным (без _), а виджет ConnectivityStatus присутствует и уникален в дереве виджетов.

Надеюсь, это поможет!

person na2axl    schedule 08.05.2020