最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

flutter - AutoDisposeFamilyNotifier does not cache results for previously used arguments - Stack Overflow

programmeradmin2浏览0评论

I want to create a provider that allows me to receive arguments to update the result, similar to FamilyNotifier, but also a provider that gets disposed once no listeners are attached, such as when I pop the current screen, just like AutoDisposeNotifier.

I'm trying to combine both behaviors using AutoDisposeFamilyNotifier, but I’ve noticed that it doesn’t work as expected. This provider is disposed of each time I change the argument passed to it, even if the same argument was used before. I’m not sure if this is the intended behavior, but ideally, I would like the provider to be disposed of only when I pop the current screen.

My goal is to create a new state each time I navigate to the screen where this provider is used, cache results for arguments that have already been passed, and dispose the provider when I pop the current screen.

Is there a way to achieve this? I tried using ref.keepAlive, but this essentially turns AutoDisposeFamilyNotifier into a FamilyNotifier, preventing the provider from being disposed of when I pop the screen.

I’ve included a minimal example to illustrate the issue more clearly.

Thanks in advance!

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

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

final counterProvider = StateProvider<int>((_) => 0);

final resultProvider = NotifierProvider.family.autoDispose<CounterResultNotifier, ({bool loading, int result}), int>(CounterResultNotifier.new);

class CounterResultNotifier extends AutoDisposeFamilyNotifier<({bool loading, int result}), int> {
  @override
  ({bool loading, int result}) build(int arg) {
    print('build with arg: $arg');

    ref.onDispose(() {
      print('dispose with arg: $arg');
    });

    update();

    return (loading: true, result: 0);
  }

  Future<void> update() async {
    await Future.delayed(Duration(seconds: 2));
    state = (loading: false, result: arg);
  }
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen()
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FilledButton(
              onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => CounterScreen())), 
              child: Text('Go to Counter')
            )
          ],
        ),
      ),
    );
  }
}

class CounterScreen extends ConsumerWidget {
  const CounterScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(title: Text('Riverpod Issue'),),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          spacing: 30.0,
          children: [
            Consumer(
              builder: (_, ref, __) {
                final counter = ref.watch(counterProvider);

                final result = ref.watch(resultProvider(counter));

                if(result.loading) {
                  return CircularProgressIndicator();
                }

                return Text('${result.result}');
              }
            ),

            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              spacing: 60,
              children: [
                FloatingActionButton(
                  heroTag: "remove",
                  onPressed: () => ref.read(counterProvider.notifier).update((state) => state - 1), 
                  child: Icon(Icons.remove)
                ),


                FloatingActionButton(
                  heroTag: "add",
                  onPressed: () => ref.read(counterProvider.notifier).update((state) => state + 1), 
                  child: Icon(Icons.add)
                )
              ],
            )
          ],
        ),
      ),
    );
  }
}
发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>