Flutter - 如果屏幕上未加载数据,则刷新页面

发布于 2025-01-15 06:50:50 字数 6974 浏览 0 评论 0原文

我的 initState 函数中有一个 Future.delayed ,它获取 jwt 缓存并使用它来获取登录用户的详细信息。 initState 函数是:

  @override
  void initState() {
    super.initState();
    Future.delayed(Duration.zero, () async {
      final token = await CacheService().readCache(key: "jwt");
      if (token != null) {
        await Provider.of<ProfileNotifier>(context, listen: false)
            .decodeUserData(
          context: context,
          token: token,
          option: 'home',
        );
      }
    });
  }

现在它确实可以工作,我确实获得了数据,但在第一次运行时没有。我必须热重新加载模拟器,或者导航到另一个页面,然后返回该页面以重建自身并在屏幕上显示数据。我不明白为什么它不显示第一次运行时的数据。

我尝试添加条件来构建方法,以便在数据不存在时再次运行 setState 和 initState 。

  @override
  Widget build(BuildContext context) {
    ProfileModel profile =
        Provider.of<ProfileNotifier>(context, listen: false).profile;
    if (profile.profileName.isEmpty) {
      print('reloading to get data');
      initState();
      setState(() {});
    } ....

它不会运行,因为数据在那里,但不知何故它不会显示在屏幕上,直到刷新页面。我似乎无法弄清楚这里的问题。请帮忙。

编辑:ProfileNotifier 类:

class ProfileNotifier extends ChangeNotifier {
  final ProfileAPI _profileAPI = ProfileAPI();
  final CacheService _cacheService = CacheService();

  ProfileModel _profile = ProfileModel(
    profileImage: "",
    profileName: "",
    profileBio: "",
  );

  AccountModel _account = AccountModel(
    userId: "",
    userEmail: "",
    userPassword: "",
  );

  ProfileModel get profile => _profile;
  AccountModel get account => _account;

  Future decodeUserData({
    required BuildContext context,
    required String token,
    required String option,
  }) async {
    try {
      _profileAPI.decodeUserData(token: token).then((value) async {
        final Map<String, dynamic> parsedData = await jsonDecode(value);
        var userData = parsedData['data'];
        if (userData != null) {
          List<String>? userProfileData = await _cacheService.readProfileCache(
            key: userData['userData']['id'],
          );
          if (userProfileData == null) {
            final isProfileAvailable =
                await Provider.of<ProfileNotifier>(context, listen: false)
                    .getProfile(
              context: context,
              userEmail: userData['userData']['userEmail'],
            );
            if (isProfileAvailable is ProfileModel) {
              _profile = isProfileAvailable;
            } else {
              _account = AccountModel(
                userId: userData['userData']['id'],
                userEmail: userData['userData']['userEmail'],
                userPassword: userData['userData']['userPassword'],
              );
              _profile = ProfileModel(
                profileImage: '',
                profileName: '',
              );
            }
            if (option != 'profileCreation' && isProfileAvailable == false) {
              Navigator.of(context).pushReplacementNamed(ProfileCreationRoute);
            }
          } else {
            _account = AccountModel(
              userId: userData['userData']['id'],
              userEmail: userData['userData']['userEmail'],
              userPassword: userData['userData']['userPassword'],
            );
            _profile = ProfileModel(
              profileName: userProfileData[3],
              profileImage: userProfileData[4],
              profileBio: userProfileData[5],
            );
          }
        } else {
          Navigator.of(context).pushReplacementNamed(AuthRoute);
        }
        notifyListeners();
      });
    } catch (e) {
      debugPrint('account/profileNotifier decode error: ' + e.toString());
    }
  }

  Future getProfile({
    required BuildContext context,
    required String userEmail,
  }) async {
    try {
      var getProfileData = await _profileAPI.getProfile(
        userEmail: userEmail,
      );
      final Map<String, dynamic> parsedProfileData =
          await jsonDecode(getProfileData);
      bool isReceived = parsedProfileData["received"];
      dynamic profileData = parsedProfileData["data"];
      if (isReceived && profileData != 'Fill some info') {
        Map<String, dynamic> data = {
          'id': (profileData['account']['id']).toString(),
          'userEmail': profileData['account']['userEmail'],
          'userPassword': profileData['account']['userPassword'],
          'profile': {
            'profileName': profileData['profileName'],
            'profileImage': profileData['profileImage'],
            'profileBio': profileData['profileBio'],
          }
        };
        AccountModel accountModel = AccountModel.fromJson(
          map: data,
        );
        return accountModel;
      } else {
        return false;
      }
    } catch (e) {
      debugPrint('profileNotifier getProfile error: ' + e.toString());
    }
  }

  Future setProfile({
    required String profileName,
    required String profileImage,
    required String profileBio,
  }) async {
    _profile.profileName = profileName;
    _profile.profileImage = profileImage;
    _profile.profileBio = profileBio;
    await _cacheService.writeProfileCache(
      key: _account.userId,
      value: [
        _account.userId,
        _account.userEmail,
        _account.userPassword as String,
        profileName,
        profileImage,
        profileBio,
      ],
    );
    notifyListeners();
  }
}

我删除了通知程序中的创建配置文件、更新配置文件和配置文件图像上传方法,因为此处不涉及它们。

使用shared_preferences包的CacheService类是:

class CacheService {
  Future<String?> readCache({
    required String key,
  }) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    String? cache = await sharedPreferences.getString(key);
    return cache;
  }

  Future<List<String>?> readProfileCache({
    required String key,
  }) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    List<String>? cachedData = await sharedPreferences.getStringList(key);
    return cachedData;
  }

  Future writeCache({required String key, required String value}) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    await sharedPreferences.setString(key, value);
  }

  Future writeProfileCache(
      {required String key, required List<String> value}) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    await sharedPreferences.setStringList(key, value);
  }

  Future deleteCache({
    required BuildContext context,
    required String key,
  }) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    await sharedPreferences.remove(key).whenComplete(() {
      Navigator.of(context).pushReplacementNamed(AuthRoute);
    });
  }
}

我不确定代码是否完全优化。欢迎任何改进。谢谢。

I have a Future.delayed in my initState function that gets jwt cache and uses it to get the logged in user's details. The initState function is:

  @override
  void initState() {
    super.initState();
    Future.delayed(Duration.zero, () async {
      final token = await CacheService().readCache(key: "jwt");
      if (token != null) {
        await Provider.of<ProfileNotifier>(context, listen: false)
            .decodeUserData(
          context: context,
          token: token,
          option: 'home',
        );
      }
    });
  }

Now it does work and I do get the data but not on the first run. I have to either hot reload the emulator or navigate to another page and come back for the page to rebuild itself and show the data on screen. I don't understand why it doesn't show the data on the first run itself.

I tried to add conditional to build method to run setState and initState again if data is not there.

  @override
  Widget build(BuildContext context) {
    ProfileModel profile =
        Provider.of<ProfileNotifier>(context, listen: false).profile;
    if (profile.profileName.isEmpty) {
      print('reloading to get data');
      initState();
      setState(() {});
    } ....

And it doesn't run coz the data is there but somehow it doesn't show up on the screen till the page is refreshed. I can't seem to figure out the problem here. Please help.

EDIT: ProfileNotifier class:

class ProfileNotifier extends ChangeNotifier {
  final ProfileAPI _profileAPI = ProfileAPI();
  final CacheService _cacheService = CacheService();

  ProfileModel _profile = ProfileModel(
    profileImage: "",
    profileName: "",
    profileBio: "",
  );

  AccountModel _account = AccountModel(
    userId: "",
    userEmail: "",
    userPassword: "",
  );

  ProfileModel get profile => _profile;
  AccountModel get account => _account;

  Future decodeUserData({
    required BuildContext context,
    required String token,
    required String option,
  }) async {
    try {
      _profileAPI.decodeUserData(token: token).then((value) async {
        final Map<String, dynamic> parsedData = await jsonDecode(value);
        var userData = parsedData['data'];
        if (userData != null) {
          List<String>? userProfileData = await _cacheService.readProfileCache(
            key: userData['userData']['id'],
          );
          if (userProfileData == null) {
            final isProfileAvailable =
                await Provider.of<ProfileNotifier>(context, listen: false)
                    .getProfile(
              context: context,
              userEmail: userData['userData']['userEmail'],
            );
            if (isProfileAvailable is ProfileModel) {
              _profile = isProfileAvailable;
            } else {
              _account = AccountModel(
                userId: userData['userData']['id'],
                userEmail: userData['userData']['userEmail'],
                userPassword: userData['userData']['userPassword'],
              );
              _profile = ProfileModel(
                profileImage: '',
                profileName: '',
              );
            }
            if (option != 'profileCreation' && isProfileAvailable == false) {
              Navigator.of(context).pushReplacementNamed(ProfileCreationRoute);
            }
          } else {
            _account = AccountModel(
              userId: userData['userData']['id'],
              userEmail: userData['userData']['userEmail'],
              userPassword: userData['userData']['userPassword'],
            );
            _profile = ProfileModel(
              profileName: userProfileData[3],
              profileImage: userProfileData[4],
              profileBio: userProfileData[5],
            );
          }
        } else {
          Navigator.of(context).pushReplacementNamed(AuthRoute);
        }
        notifyListeners();
      });
    } catch (e) {
      debugPrint('account/profileNotifier decode error: ' + e.toString());
    }
  }

  Future getProfile({
    required BuildContext context,
    required String userEmail,
  }) async {
    try {
      var getProfileData = await _profileAPI.getProfile(
        userEmail: userEmail,
      );
      final Map<String, dynamic> parsedProfileData =
          await jsonDecode(getProfileData);
      bool isReceived = parsedProfileData["received"];
      dynamic profileData = parsedProfileData["data"];
      if (isReceived && profileData != 'Fill some info') {
        Map<String, dynamic> data = {
          'id': (profileData['account']['id']).toString(),
          'userEmail': profileData['account']['userEmail'],
          'userPassword': profileData['account']['userPassword'],
          'profile': {
            'profileName': profileData['profileName'],
            'profileImage': profileData['profileImage'],
            'profileBio': profileData['profileBio'],
          }
        };
        AccountModel accountModel = AccountModel.fromJson(
          map: data,
        );
        return accountModel;
      } else {
        return false;
      }
    } catch (e) {
      debugPrint('profileNotifier getProfile error: ' + e.toString());
    }
  }

  Future setProfile({
    required String profileName,
    required String profileImage,
    required String profileBio,
  }) async {
    _profile.profileName = profileName;
    _profile.profileImage = profileImage;
    _profile.profileBio = profileBio;
    await _cacheService.writeProfileCache(
      key: _account.userId,
      value: [
        _account.userId,
        _account.userEmail,
        _account.userPassword as String,
        profileName,
        profileImage,
        profileBio,
      ],
    );
    notifyListeners();
  }
}

I've removed the create profile, update profile and profile image upload methods in the notifier as they are not involved here.

The CacheService class using shared_preferences package is:

class CacheService {
  Future<String?> readCache({
    required String key,
  }) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    String? cache = await sharedPreferences.getString(key);
    return cache;
  }

  Future<List<String>?> readProfileCache({
    required String key,
  }) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    List<String>? cachedData = await sharedPreferences.getStringList(key);
    return cachedData;
  }

  Future writeCache({required String key, required String value}) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    await sharedPreferences.setString(key, value);
  }

  Future writeProfileCache(
      {required String key, required List<String> value}) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    await sharedPreferences.setStringList(key, value);
  }

  Future deleteCache({
    required BuildContext context,
    required String key,
  }) async {
    final SharedPreferences sharedPreferences =
        await SharedPreferences.getInstance();
    await sharedPreferences.remove(key).whenComplete(() {
      Navigator.of(context).pushReplacementNamed(AuthRoute);
    });
  }
}

I'm not sure if the code is completely optimized. Any improvement is welcome. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文