Search code examples
jsonfluttersharedpreferences

How to save a response data into sharedPreference in flutter


I want to save the user details response in sharedPreference so that user can resume the app anytime as long as he/she doesn't log out but this keeps on returning null when I tried to retrieved the data that I stored in sharedpreference. I don't really know how to go about it.

This is the data that my backend returned after a successful login:

{"message":"Login Successfully","data":{"id":1,"type":1,"name":"Elijah","email":"ukemedmet@gmail.com","profileImage":"http://192.168.229.108:8080/download/887c17f8-1f45-450e-8e45-a12b8a307e5a","accessToken":"OPXI5X98lcdvjUjgRiZTYvcDSjH2"},"code":200}

If I try to print the result.toString in the asyncPostData method, I get the instance of UserLoginResponseEntity and result.data is returning the instance of UserItem instead of the json data. All I need is to know how to store the "data" item which contains name, email, etc of the logged in user in sharedPreference. The "data" item is a json object that contains all the user's info as shown in the response

class AppApi {
  static login({LoginRequestEntity? loginRequestEntity}) async {
    var response = await NetworkRequestUtil().post(
      AppConstants.LOGIN_URL,
      data: loginRequestEntity!.toJson(),
    );
    return UserLoginResponseEntity.fromJson(response);
  }
}


Future<void> asyncPostData(LoginRequestEntity loginRequestEntity) async {
    var result = await AppApi.login(loginRequestEntity: loginRequestEntity);
    if (result.code == 200) {
      try {
        //method to save the user data in sharedpreference
         Global.service.setString(
             AppConstants.STORAGE_USER_PROFILE_KEY, jsonEncode(result.data));

        if (context.mounted) {
          Navigator.of(context)
              .pushNamedAndRemoveUntil("/home", (route) => false);
        }
      } catch (e) {
        print("Local storage info saving error ${e.toString()}");
      }
    } else {
      toastInfo(msg: "Error Occurred");
    }
  }

class UserLoginResponseEntity {
  int? code;
  String? msg;
  UserItem? data;

  UserLoginResponseEntity({
    this.code,
    this.msg,
    this.data,
  });

  factory UserLoginResponseEntity.fromJson(Map<String, dynamic> json) =>
      UserLoginResponseEntity(
          code: json["code"],
          msg: json["message"],
          data: UserItem.fromJson(json["data"]));
}

class UserItem {
  String? token;
  String? name;
  String? description;
  String? avatar;
  int? type;
  String? email;

  UserItem({
    this.token,
    this.name,
    this.description,
    this.avatar,
    this.type,
    this.email,
  });

  factory UserItem.fromJson(Map<String, dynamic> json) => UserItem(
      token: json["accessToken"],
      name: json["name"],
      avatar: json["profileImage"],
      type: json["type"],
      email: json["email"]);

  Map<String, dynamic> toJson() => {
        "accessToken": token,
        "name": name,
        "profileImage": avatar,
        "type": type,
        "email": email
      };
}


class StorageService {
  late SharedPreferences _pref;
  Future<StorageService> initSharedPreference() async {
    _pref = await SharedPreferences.getInstance();
    return this;
  }

//method to return the stored user data if it's not null
//this method always returns null I don't know why my data wasn't saved in sharedpreference
UserItem? getUserProfile() {
    var offlineProfile =
        _pref.getString(AppConstants.STORAGE_USER_PROFILE_KEY) ?? "";
    if (offlineProfile.isNotEmpty) {
      UserItem.fromJson(jsonDecode(offlineProfile));
    }
    return null;
  }

Solution

  • Update your class to override the toString medthod. This would display your class in a readable format when you print:

    class UserLoginResponseEntity {
      int? code;
      String? msg;
      UserItem? data;
    
      UserLoginResponseEntity({
        this.code,
        this.msg,
        this.data,
      });
    
      factory UserLoginResponseEntity.fromJson(Map<String, dynamic> json) =>
          UserLoginResponseEntity(
              code: json["code"],
              msg: json["message"],
              data: UserItem.fromJson(json["data"]));
    
      @override
      String toString() {
        return 'UserLoginResponseEntity{code: $code, msg: $msg, data: $data}';
      }
    }
    
    class UserItem {
      String? token;
      String? name;
      String? description;
      String? avatar;
      int? type;
      String? email;
    
      UserItem({
        this.token,
        this.name,
        this.description,
        this.avatar,
        this.type,
        this.email,
      });
    
      factory UserItem.fromJson(Map<String, dynamic> json) => UserItem(
          token: json["accessToken"],
          name: json["name"],
          avatar: json["profileImage"],
          type: json["type"],
          email: json["email"]);
    
      Map<String, dynamic> toJson() => {
            "accessToken": token,
            "name": name,
            "profileImage": avatar,
            "type": type,
            "email": email
          };
    
      @override
      String toString() {
        return 'UserItem{token: $token, name: $name, description: $description, avatar: $avatar, type: $type, email: $email}';
      }
    }
    

    However, you can't save a Dart class using shared preferences but you can save strings to do that DO NOT use the classes' toString method; do this instead:

    Use the toJson method in UserItem to convert result.data to Map<String, dynamic>; then encode that data to a Json string like so:

    final userItemJsonString =  json.encode(result.data.toJson());
    

    To get the UserItem object back from shared pref., decode the Json string that is returned:

    final userItem = UserItem.fromJson(json.decode(userItemJsonString))