简体   繁体   English

如何使用 StateNotifierProvider 在 fcm 处理程序中更新 state?

[英]How to update state in a fcm handler with StateNotifierProvider?

In my Flutter app i need being able to react on incoming fcm messages which can instruct the app to go a different navigation tab by having a corresponding key/value pair in its data payload.在我的 Flutter 应用程序中,我需要能够对传入的 fcm 消息做出反应,这些消息可以通过在其数据有效负载中具有相应的键/值对来指示应用程序到 go 不同的导航选项卡。 Currently the selected index is stored in the stateful widget which also hosts the bottom navigation bar:当前,选定的索引存储在有状态小部件中,该小部件还托管底部导航栏:

@override
  Widget build(BuildContext context) {
    presentTicketsModel = ref.watch(presentTicketsModelProvider);
    contractsModel = ref.watch(contractsModelProvider);
    return Scaffold(
      body: PersistentTabs(
        currentTabIndex: index,
        screenWidgets: buildPages(),
      ),
      bottomNavigationBar: NavigationBar(
        height: 60,
        selectedIndex: index,
        onDestinationSelected: (index) => setState(() {
          this.index = index;
        }),
        destinations: _buildNavigationDestinations(),
      ),
    );
  }

With the new challenge i thought about moving that state index into a separate object and use Riverpod's StateNotifierProvider to provide that state object, as it is described in the official doc ( https://riverpod.dev/docs/providers/state_notifier_provider ).面对新的挑战,我考虑将 state 索引移动到单独的 object 中,并使用 Riverpod 的 StateNotifierProvider 提供 state object,如官方文档 ( https://riverpod.deviders/docs ) 中所述。

What i don't get is: How can the following service class (which listens for incoming fcm messages) get hold of that state object and update the index in order that the watching view class gets notified and can switch to the targeted navigation tab?我不明白的是:以下服务 class(侦听传入的 fcm 消息)如何获取 state object 并更新索引,以便观察视图 class 得到通知并可以切换到目标导航选项卡?

class PushNotificationService {
  final fcm = FirebaseMessaging.instance;

  Future initialise() async {
    print('initialising push notification service...');
    }

    /// foreground handler
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('onMessage: $message');
      // here the state change would be done
    });

    /// handler if the app has been opened from a background state
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('onMessageOpenedApp: $message');
    });

  }
}

Or asked differently: How does this service class get passed a ProviderReference in order to access the mentioned state object and change the index value?或者以不同的方式询问:该服务 class 如何通过 ProviderReference 以访问提到的 state object 并更改索引值?

The service currently is registered with GetIt as a lazy singleton:该服务目前在 GetIt 注册为一个懒惰的 singleton:

GetIt locator = GetIt.instance;

void setupLocator() {
  locator.registerLazySingleton(PushNotificationService.new);
}

The initialise method can have a Ref parameter like so: initialise方法可以有一个Ref参数,如下所示:

class PushNotificationService {
  final fcm = FirebaseMessaging.instance;

  Future initialise(WidgetRef ref) async {
    print('initialising push notification service...');
    }

    /// foreground handler
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
     // Use ref.read here -> ref.read();
    });

    /// handler if the app has been opened from a background state
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('onMessageOpenedApp: $message');
    });

  }
}

Then you can pass a ref when calling initialise.然后你可以在调用初始化时传递一个ref。

PushNotificationService.initialise(ref);

If you'd be calling initialise in a widget, use WidgetRef instead of Ref如果您要在小部件中调用initialise ,请使用WidgetRef而不是Ref

EDIT: Where to pass ref (notice that we're using WidgetRef now)编辑:在哪里传递 ref(注意我们现在正在使用WidgetRef

Follow these steps按着这些次序

  • Make MyApp a ConsumerStatefulWidget使MyApp成为ConsumerStatefulWidget
  • Call PushNotificationService.initialise(ref);调用PushNotificationService.initialise(ref); in initStateinitState

Full code:完整代码:


void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends ConsumerStatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends ConsumerState<MyApp> {

  @override
  initState(){
   PushNotificationService.initialise(ref);
   super.initState();
  }
  
class _MyAppState extends ConsumerState<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "App",
      home: Home(),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM