Флаттер: Как получить данные из api один раз и использовать их для разных экранов

#flutter

Вопрос:

Как я могу получить данные, например сведения о пользователе, один раз на одном экране и использовать их на другом экране?

Я хочу получить данные один раз, и я могу использовать данные на другом экране, и мне не нужно будет получать их снова. Спасибо.

Ответ №1:

Если я правильно понял ваш вопрос, вы знаете, как получить данные пользователя, но не хотите загружать их несколько раз, а скорее использовать данные из разных виджетов.

Общие настройки могут сработать, но я не рекомендую это делать, они предназначены для хранения только примитивных данных.

Простым, но не идеальным решением является создание одноэлементного класса прикладного уровня. Вы можете загружать/обновлять данные пользователя, и к ним можно получить доступ отовсюду в вашем приложении. Что-то вроде:

 class UserDetails {
   // define every member data here that you will load
   static late String name;
   static late String email;
   
   // this makes it singleton-like
   factory UserDetails() => UserDetails._internal();
   UserDetails._internal();
}
 

Вы можете установить / получить сведения о пользователе, такие как:

 UserDetails.name
 

Более похожим на трепет подходом было бы рассмотрение сведений о пользователе как состояния вашего приложения и использование уведомителей для «трансляции» этих значений по всему дереву виджетов. Хорошей отправной точкой было бы прочитать эту часть документации.

Вот очень простой пример того, как загрузить данные из API и сохранить их в одноэлементном классе. Пример ограничен только одними данными (электронной почтой), но, конечно, вы можете расширить его. В реальном приложении потребуется много обработки ошибок, в этом примере предполагается, что все в порядке:

 class UserDetails {
  static late String email;

  factory UserDetails() => UserDetails._internal();
  UserDetails._internal();

  static Future<void> getUserDetails() async {
    // API_BASE_URL for example: "domain.com"
    // API_URL for example: "/user/details"
    // AUTHORIZATION: optional, skip headers part if you don't need
    final response = await http.get(
        Uri.https(API_BASE_URL, API_URL),
        headers: {'authorization': AUTHORIZATION});

    // here we decode the response body, assuming
    // that data is under "data" tag in response JSON
    final responseData = jsonDecode(response.body)["data"];

    // and within it we have an "email" tag with the user's mail
    // here 'email' is the static member of this class
    // and we set the value from the API response
    email = responseData["name"];
  }
}
 

Будьте осторожны, для простоты здесь нет обработки ошибок. Мы даже не проверяем, имеет ли ответ код статуса 200. (Вы можете легко добавить его, подсказка: response.StatusCode содержит его.) Кроме того, другие вещи могут пойти не так, сбой сервера и т.д.

Итак, как загрузить данные и получить к ним доступ? Функция getUserDetails является асинхронной, поэтому где-то в вашем коде (где-то в начале, я думаю) вам нужно вызвать ее один раз из другой асинхронной функции, чтобы вы могли ее дождаться. Убедитесь, что вы нашли место, где он больше не будет запускаться, и проверьте с помощью консоли отладки! В следующей строке будут получены данные из API и сохранены в статическом элементе:

 await UserDetails.getUserDetails();
 

Если это сделано, вы можете читать и записывать данные пользователя, загруженные из вашего API, из любого места вашего приложения, не перезагружая его:

 print(UserDetails.email);
UserDetails.email = "new email";
 

Комментарии:

1. Я использую http для получения данных из API. Я также могу создать одноэлементный класс для получения данных?

2. Я бы предпочел создать класс модели, содержащий все элементы, которые отправляет ваш API. Когда вы получаете свои данные, вы создаете новый экземпляр этого класса, объект.

3. Например, очень часто API возвращает не одни данные, а коллекцию, массив. В этом случае вы можете преобразовать результат (возможно, JSON) в список объектов.

4. Ознакомьтесь с этим руководством здесь: flutter.dev/документы/кулинарная книга/сеть/получение данных .

5. У меня уже есть класс модели сведений о пользователе, что вы имеете в виду, если я создам новый класс для хранения данных, когда получу данные? Потому что я хочу получить доступ к данным в другом виджете без повторного вызова api.

Ответ №2:

вы можете попробовать использовать общие настройки для хранения и извлечения данных, когда каждый раз, когда вы хотите их использовать

Ответ №3:

Запишите свою функцию API в другой файл см. Ниже:

 Future apiCall() async {
  var url = 'put your API url here';
  var result = await http.get(url);
  if (result.statusCode == 200) {
    return json.decode(result.body);
  } else {
    throw Exception('Failed');
  }
}
 

затем вызовите свою функцию API в другом файле, когда вы вызываете API ниже:

 FutureBuilder(
      future: apiCall(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          if (snapshot.data.length > 0) {
            return Text(
              
                  '${snapshot.data[0]['name']}'
                  
              style: TextStyle(
                fontWeight: FontWeight.bold,
                wordSpacing: 200,
                fontSize: 20,
              ),
             
            );
          } else {
            return Text(
              '❌ No Data Found',
              style: TextStyle(
                color: Colors.red,
              ),
            );
          }
        }
        return CircularProgressIndicator();
      },
    ),