flutter - 从不同的有状态小部件更新值

标签 flutter

因此,我正在尝试更新父小部件或子小部件的值。这是父部件

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => new _MainPageState();
}

class _MainPageState extends State<MainPage> {
  GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey();
  NotificationCounter _notificationCounter =
      new NotificationCounter(initialCount: 0);
  ................
      _fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        _notificationCounter.increment();
      },
      onLaunch: (Map<String, dynamic> message) async {
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => NotificationPage()),
        );
      },
      onResume: (Map<String, dynamic> message) async {
        print("resume");
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => NotificationPage()),
        );
      },
    );

}

然后我有这个子statefulwidget

class CustomAppbar extends StatefulWidget implements PreferredSizeWidget {
  final double height;
  final String reqFrom;
  int Notificationcounter;

  CustomAppbar(
      {Key key,
      @required this.height,
      @required this.reqFrom,
      this.Notificationcounter})
      : super(key: key);

  @override
  _CustomAppbarState createState() => new _CustomAppbarState();

  @override
  // TODO: implement preferredSize
  Size get preferredSize => Size.fromHeight(height);
}

class _CustomAppbarState extends State<CustomAppbar> {
  String userId = "", userFullname = "";
  String appName, packageName, version = "", buildNumber;
  NotificationCounter _notificationCounter = new NotificationCounter();
........
}

这是我的 NotificationCounter

class NotificationCounter {
  int initialCount = 0;
  BehaviorSubject<int> _subjectCounter;

  NotificationCounter({this.initialCount}) {
    _subjectCounter = new BehaviorSubject<int>.seeded(
        this.initialCount); //initializes the subject with element already
  }

  Observable<int> get counterObservable => _subjectCounter.stream;

  void increment() {
    initialCount++;
    _subjectCounter.sink.add(initialCount);
  }

  void setValue(int newVal){
    initialCount = newVal;
    _subjectCounter.sink.add(newVal);
  }

  void decrement() {
    initialCount--;
    _subjectCounter.sink.add(initialCount);
  }

  void dispose() {
    _subjectCounter.close();
  }
}

好的,在 CustomAppbar 类中,我用这个更新计数器值

  Future<dynamic> _CountNotification() async {
    prefs = await SharedPreferences.getInstance();
    try {
      final response = await http.post(
          Configuration.url + "api/countNotification",
          body: {"userId": prefs.getString("userId")});
      final JsonDecoder _decoder = new JsonDecoder();
      var notificationCount = _decoder.convert(response.body);
      setState(() {
        _notificationCounter.setValue(notificationCount);
      });
    } catch (e) {
      return null;
    }
  }

例如,它将值设置为 5。然后,从 MainPage() 有一个新的通知会增加该值,但该值没有改变。

我该如何解决?我错过了什么 ?提前致谢,对不起我的英语。

我正在关注这个 https://medium.com/flutter-community/why-use-rxdart-and-how-we-can-use-with-bloc-pattern-in-flutter-a64ca2c7c52d

最佳答案

方法一

使 NotificationCounter 成为单例。


class NotificationCounter {

  //Private Constructor
  NotificationCounter._();

  static NotificationCounter _instance;

  factory NotificationCounter.instance() {
    if (_instance == null) {
      _instance = NotificationCounter._();
    }
    return _instance;
  }

}

并且到处使用NotificationCounter.instance()

方法二

使用InheritedWidget


class InheritedNotificationCounter extends InheritedWidget {
  final NotificationCounter notificationCounter;

  InheritedNotificationCounter({this.notificationCounter, Widget child}) : super(child: child);

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) {
    // TODO: https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
    return true;
  }

  static InheritedNotificationCounter of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(InheritedNotificationCounter) as InheritedNotificationCounter);
  }
}


像这样构造您的 MaterialApp

  final NotificationCounter notificationCounter = NotificationCounter() /*or NotificationCounter.instance() // Dependong on the way you implement it*/;
  @override
  Widget build(BuildContext context) {
    return InheritedNotificationCounter(
      notificationCounter: notificationCounter,
      child: MaterialApp(
        ...
      ),
    );
  }

所以,现在所有的小部件都可以像这样访问NotificationCounter InheritedNotificationCounter.of(context).notificationCounter

希望对您有所帮助。


继续使用 RxDart 获取通知

按照评论中的要求

您可以在此处使用 BLOC 来管理通知。 FCM/NotificationService 会向 BLOC 发送通知,所有需要通知的 widget 都可以订阅通知。示例实现

Bloc

import 'package:rxdart/rxdart.dart';

class LocalNotification {
  final String type;
  final Map data;

  LocalNotification(this.type, this.data);
}

class NotificationsBloc {
  NotificationsBloc._internal();

  static final NotificationsBloc instance = NotificationsBloc._internal();

  final BehaviorSubject<LocalNotification> _notificationsStreamController = BehaviorSubject<LocalNotification>();

  Stream<LocalNotification> get notificationsStream {
    return _notificationsStreamController;
  }

  void newNotification(LocalNotification notification) {
    _notificationsStreamController.sink.add(notification);
  }

  void dispose() {
    _notificationsStreamController?.close();
  }
}

FCM 监听器(NotificationService)

import 'package:firebase_messaging/firebase_messaging.dart';

import 'notifications_bloc.dart';

class LocalNotificationService {
  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  bool _started = false;

  LocalNotificationService._internal();

  static final LocalNotificationService instance = LocalNotificationService._internal();

  // ********************************************************* //
  // YOU HAVE TO CALL THIS FROM SOMEWHERE (May be main widget)
  // ********************************************************* //
  void start() {
    if (!_started) {
      _start();
      _started = true;
      _refreshToken();
    }
  }

  void _refreshToken() {
    _firebaseMessaging.getToken().then(_tokenRefresh, onError: _tokenRefreshFailure);
  }

  void _start() {
    _firebaseMessaging.requestNotificationPermissions();
    _firebaseMessaging.onTokenRefresh.listen(_tokenRefresh, onError: _tokenRefreshFailure);
    _firebaseMessaging.configure(
      onMessage: _onMessage,
      onLaunch: _onLaunch,
      onResume: _onResume,
    );
  }

  void _tokenRefresh(String newToken) async {
    print(" New FCM Token $newToken");
  }

  void _tokenRefreshFailure(error) {
    print("FCM token refresh failed with error $error");
  }

  Future<void> _onMessage(Map<String, dynamic> message) async {
    print("onMessage $message");
    if (message['notification'] != null) {
      final notification = LocalNotification("notification", message['notification'] as Map);
      NotificationsBloc.instance.newNotification(notification);
      return null;
    }
    if (message['data'] != null) {
      final notification = LocalNotification("data", message['data'] as Map);
      NotificationsBloc.instance.newNotification(notification);
      return null;
    }
  }

  Future<void> _onLaunch(Map<String, dynamic> message) {
    print("onLaunch $message");
    return null;
  }

  Future<void> _onResume(Map<String, dynamic> message) {
    print("onResume $message");
    return null;
  }
}

终于在您的小部件中

  Stream<LocalNotification> _notificationsStream;

  @override 
  void initState() {
    super.initState();
    _notificationsStream = NotificationsBloc.instance.notificationsStream;
    _notificationsStream.listen((notification) {
      // TODO: Implement your logic here
      // You might want to incement notificationCouter using above mentioned logic.
      print('Notification: $notification');
    });
  }

  @override
  void dispose() {
    _notificationsStream?.dispose();
  }

关于flutter - 从不同的有状态小部件更新值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58132067/

相关文章:

dart - 如何在 Dart 中获取字符串中的最后 n 个字符?

flutter - 在 Flutter Web 中嵌入 Youtube 视频

javascript - Flutter - 方法 'then' 被调用为 null

flutter - 具有不等权重元素的行

flutter - 如何在HashMap中将元素添加到ArrayList中? DART和Flutter

flutter - 在 Flutter 中显示用户友好的错误页面而不是异常

当类用作值而不是字符串时, flutter 下拉失败

flutter 从 url 下载图片

flutter - 更新 Flutter 后 StaggeredGridView 不滚动

flutter - 无法从 flutter 应用程序正确打开 url scheme