【问题标题】:Flutter: Access SharedPreferences Provider / ChangeNotifier in a Stream ClassFlutter:在 Stream 类中访问 SharedPreferences Provider / ChangeNotifier
【发布时间】:2020-11-03 19:30:56
【问题描述】:

我在 StackoverFlow 中环顾四周,并没有找到解决此问题的方法。 设想: 我有一个带有 ChangeNotifier 类的 Flutter SharedPreferences Provider,它将使用当前登录用户信息进行更新。

简化内容:

class SharedPreferences {
  final String userId;
  final String userName;

  SharedPreferences({
    @required this.userId,
    @required this.userName,
  });
}
class SharedPreferencesData with ChangeNotifier {
  var _sharedPreferencesData = SharedPreferences(
    userId: 'testUserId',
    userName: 'testUserName',
  );}

还有一个包含 DataBaseServices 类的 database.dart 文件,用于从快照中获取 FireStore 流:

class DatabaseService {
  final CollectionReference companiesProfilesCollection =
      Firestore.instance.collection('companiesProfiles');

  List<CompanyProfile> _companiesProfilesFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc) {
      return CompanyProfile(
        docId: doc.documentID,
        companyName: doc.data['companyName'] ?? '',
        maxLocationsNumber: doc.data['maxLocationsNumber'] ?? 0,
        maxUsersNumber: doc.data['maxUsersNumber'] ?? 0,
      );
    }).toList();
  }

  Stream<List<CompanyProfile>> get getCompaniesProfiles {
    return companiesProfilesCollection
        .where('userId', isEqualTo: _userIdFromProvider) 
        // My problem is above -----
        .snapshots()
        .map(_companiesProfilesFromSnapshot);
  }
}

我不想获取整个 Stream 数据,因为它对于其他 Stream 来说可能很大,我只想在 .where('userId', isEqualTo:_userIdFromProvider) 下传递用户 ID。

  • 我无法访问此类中的上下文以从 Provider 获取数据

  • 无法将 userId 发送到 getCompaniesProfiles getter,因为 getter 不带参数

  • 如果我将此 getter 转换为常规方法,我将无法将用户 ID 发送给它,因为它必须在 void main() {runApp(MyApp());} / return MultiProvider 下运行(提供者:[ 到那时我无法使用不包含提供者信息的上下文调用 fetch sharedPreferences ...

  • 无法弄清楚如何在此类中接收上下文作为构造函数,当我这样做时,我得到了以下只有静态成员可以在类 DatabaseService 的初始化程序中访问

我还是一个初学者,所以如果你能与我分享处理这个问题的最佳方法,我将不胜感激。 谢谢!

**************** 通过添加以下内容重新编辑:************** 我正在尝试实现相同的场景,这是我的代码: 主文件:

return MultiProvider(
  providers: [
    ChangeNotifierProvider<SpData>(
      create: (context) => SpData(),
    ),
    ProxyProvider<SpData, DS>(
      create: (context) => DS(),
      update: (ctx, spData, previousDS) {
        print('ChangeNotifierProxyProvider RAN');
        previousDS.dbData = spData;
        return previousDS;
      },
    ),
  ],

SP 文件:

class SP {
  final String companyId;
  SP({
    @required this.companyId,
  });
}

class SpData with ChangeNotifier {
  var _sPData = SP(
    companyId: '',
  );
  void setCompanyId(String cpID) {
    final newSharedPreferences = SP(
      companyId: cpID,
    );
    _sPData = newSharedPreferences;
    print('_spData companyId:${_sPData.companyId}');
    notifyListeners();
  }

  String get getCompanyId {
    return _sPData.companyId;
  }
}

DS 文件:

class DS with ChangeNotifier {
  SpData dbData;
  void printCompanyId() {
    var companyId = dbData.getCompanyId;
    print('companyId from DataBase: $companyId');
  }
}

SpData dbData; DS 类内部不会更新。我已经添加了打印来确定什么正在运行,什么没有运行。当我运行我的代码时,main.dart 文件中的打印函数 print('ChangeNotifierProxyProvider RAN');不运行。

我错过了什么?为什么没有触发 ChangeNotifierProxyProvider 来更新 DS 文件中的 dbData?谢谢!

【问题讨论】:

    标签: flutter dart flutter-provider


    【解决方案1】:

    您可以为此使用ProxyProvider

    ProxyProvider 是一个基于其他提供者构建价值的提供者。

    你说你有一个MultiProvider,所以我猜你在这个MultiProvider 中有SharedPreferencesData 提供者,然后是DatabaseService 提供者。您需要做的是将ProxyProvider 用于DatabaseService 而不是常规提供程序,并将其基于SharedPreferencesData 提供程序。

    这是一个例子:

    MultiProvider(
      providers: [
        ChangeNotifierProvider<SharedPreferencesData>(
          create: (context) => SharedPreferencesData(),
        ),
        ProxyProvider<SharedPreferencesData, DatabaseService>(
          create: (context) => DatabaseService(),
          update: (context, sharedPreferencesData, databaseService) {
            databaseService.sharedPreferencesData = sharedPreferencesData;
            return databaseService;
          },
          dispose: (context, databaseService) => databaseService.dispose(),
        ),
      ],
      child: ...
    

    这是上面代码 sn-p 中发生的情况:

    1. 每次SharedPreferencesData 发生变化时,ProxyProvider 都会调用 update
    2. DatabaseService 将其 sharedPreferencesData 变量设置在 update 中。

    现在您可以访问DatabaseService 实例中的sharedPreferencesData,您可以轻松地做您想做的事。

    【讨论】:

    • 这种方法是完全合法的。但这对我不起作用,可能与我正在做的一些错误的实现有关,原因如下:当 sharedPreferencesData 第一次传递给 DatabaseService 时,它​​是空的。我没有在 sharedPreferencesData 中使用 notifyListeners,因为我收到一个错误:构建错误:无法 notifyListeners => setState => 在构建应用程序时重建。然而,我的应用程序在没有 notifyListeners 的情况下运行良好,因为 sharedPreferencesData 包含只会在应用程序运行和登录时更新的变量。所以我再次陷入困境,如何解决这个问题。
    • 我认为你应该用你的notifyListeners 来解决这个问题。该错误告诉我您在 build 方法中调用了 notifyListeners 是错误的。
    • 嗨 Shahin,我已经使用 WidgetsBinding.instance.addPostFrameCallback 解决了我的 notifyListeners 问题。现在 sharedPreferencesData 应该通知侦听器,因此会更新以通知代理提供者.. 我做了以下事情:
    • ChangeNotifierProvider.value(value: SharedPreferencesData(), ), ProxyProvider( create: (context) => DatabaseService(), update: (context, sharedPreferencesData, databaseService) { databaseService. sharedPreferencesData = sharedPreferencesData; return databaseService; }, // dispose: (context, databaseService) => databaseService.dispose(), ), 注意,dispose 给了我:方法 'dispose' 没有为类型 'DatabaseService' 定义.
    • 你能告诉我如何在DatabaseService中实现Dispose吗?在 DatabaseService 中: class DatabaseService { SharedPreferencesData sharedPreferencesData;最终 sPData = SharedPreferencesData().getSharedPreferencesData(); .... } 我在 DatabaseService StreamProvider 中添加了一些打印代码,但是在运行我的应用程序时,我得到以下信息: I/flutter (6795): sPData.companyId: is empty I/flutter (6795): sPData. companyId: is empty 运行 2 次,可能是第一次加载应用程序时,另一次是在 notifylisteners 之后。但 sPData.companyId 在 DatabaseService 中仍然为空
    猜你喜欢
    • 2019-12-27
    • 1970-01-01
    • 2020-12-17
    • 2021-07-20
    • 2020-11-06
    • 1970-01-01
    • 2021-01-29
    • 2020-11-01
    • 2020-02-29
    相关资源
    最近更新 更多