如果数据未显示在屏幕上,请刷新页面

Refresh page if data isn't shown on screen

我的 initState 函数中有一个 Future,它从缓存中获取 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',
        );
      }
    });
  }

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

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();
  }
}

缓存服务class:

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);
    });
  }
}

我似乎无法弄清楚这里的问题。请帮忙。

编辑:数据用于在 CircleAvatar 中显示用户的个人资料图像,如下所示:

 @override
  Widget build(BuildContext context) {
    ProfileModel profile =
        Provider.of<ProfileNotifier>(context, listen: false).profile;
    return GestureDetector(
      onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
      child: Scaffold(
        drawer: const ProfileDrawer(),
        appBar: AppBar(
          backgroundColor: Colors.white,
          leading: Row(children: [
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 9),
              child: Builder(builder: (BuildContext context) {
                return InkWell(
                  onTap: () => Scaffold.of(context).openDrawer(),
                  child: CircleAvatar(
                      maxRadius: 20.0,
                      backgroundImage: profile.profileImage.isNotEmpty
                          ? NetworkImage(profile.profileImage)
                          : null,
                      child: profile.profileImage.isEmpty
                          ? SvgPicture.asset(
                              'assets/images/profile-default.svg') 
                          : null),
                );
              }),
            ), ....

appBar中的这个CircleAvatar是重建页面后才显示的图片。目前页面上除了应用栏没有其他内容。

当我们使用ChangeNotifier时,它提供了两种访问数据的选项。它们是:

  1. Read 数据 - 您读取了数据,它不充当流或状态,而且只有一次。这就是你在你的情况下所做的。

    优势 - 只要数据只需要一次,例如 - 数学计算,你就用这个。

    缺点 - 它不监听变化,返回的数据是静态的。

  2. Watch 数据 - 您所需要的。它以状态方式提供数据,无论您在哪里使用 Watch 访问数据,只要基础数据更新,它(或使用数据中的小部件)都会更新,即使来自其他 Screens/Widgets .

    优势 - 数据结果是动态的,每当数据更新时小部件都会更新。

    缺点 - 在静态数据有效的情况下,这是不必要的,而且它可能会影响依赖于数据的任何操作。

有两种使用方式ReadWatch

  1. 包作者提供的正常功能

    //For reading the data
    var yourData = Provider.of<YourNotifier>(context, listen: false);
    
    //For watching the data
    var yourData = Provider.of<ProfileNotifier>(context, listen: true);
    
  2. BuildContext作者提供的扩展功能:

    //For reading the data
    var yourData = context.read<YourNotifier>();
    
    //For watching the data
    var yourData = context.watch<YourNotifier>();
    

所以,您需要做的是:

改变

ProfileModel profile =
        Provider.of<ProfileNotifier>(context, listen: false).profile;

ProfileModel profile =
        Provider.of<ProfileNotifier>(context, listen: true).profile;

//Or

ProfileModel profile = context.watch<ProfileNotifier>().profile;

编辑: 此外,考虑到良好的用户体验,您可以使用 bool 标志在加载数据时更新 UI,如果正在加载,则显示 CircularProgressIndicator.