Shared_preferences & initState

Bonjour à tous,

Dans une page de mon application, je construit un nombre d’objets dont j’aurai ensuite besoin pour générer ma vue. Je fais ceci dans mon initstate :

 @override
  void initState() {
    for (int i = 0; i < nombreDObjetVoulu; i++) {
      maListeDobjet.add(Objet);
    }
    super.initState();
  }

Ceci marche quand je rentre en dur dans un fichier séparé

class Setting{
static int nombreDObjetVoulu=10;
]

En m’appuyant sur le cours je voulais utiliser sharedpreferences pour pouvoir modifier ce paramètre et l’enregistrer d’une ouverture à l’autre.

class Settings{
  static Future<int> nombreDObjetVoulu() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getInt("nombreDObjetVoulu") ?? 10;
  }

  static Future<bool> setNombreDObjetVoulu(int newNumberOfObject) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.setInt("nombreDObjetVoulu", newNumberOfObject);
  }
}

Sauf qu’en remplaçant dans mon initState le nombreDObjetVoulu par Settings.nombreDObjetVoulu ca ne fonctionne pas. Je vois que je fais un truc qui cloche car il me semble avoir compris qu’on ne pouvait pas mettre un Future dans une fonction synchrone (que doit être le initstate) d’où le problème.

Du coup puis-je faire ceci dans le initstate et si oui comment ? Ou comment construire une liste d’objet avant la construction d’une View en faisant appel au shared preferencies qui determinerait le nombre à construire ?

Merci d’avance pour votre aide !

J’auto incrémente le sujet :
Je pense que la réponse réside dans le cours sur le FutureBuilder :

Je vais gratter cette piste :slight_smile:

Bonjour,
Déplace ta logique d’appel à ta classe Settings dans une fonction, qui elle sera asynchrone.
Par exemple :

_initNbrObjetVoulus() async {
    final nombre = await Settings.nombreDObjetVoulu();

    for (int i = 0; i < nombre; i++) {
      print("nombre : $i");
    }
  }

En espérant que ça réponde à ta demande :).

1 « J'aime »

Merci Lugdu pour ton aide, mais du coup j’ai déjà dans ma classe Settings déporté le nombreDObjetVoulu donc la fonction ne sera toujours pas acceptée dans mon init puisqu’elle reste asynchrone, non ?

J’ai essayé de passer par la création d’un Widget qui renvoie un FutureBuilder :
Dans mon future j’ai mis :

future : Settings.nombreDObjetsVoulus(),

et dans le builder je renvoi :

builder : (context, snapshot) {
        if (snapshot.hasData) {
          return MaPageWidget(
              parametreObjet:
                  MonObjet(nbwidget: snapshot.data));
        } else if (snapshot.hasError) {
          return Text("Loading error");
        } else {
          return CircularProgressIndicator();
        }
      },

et là le snapshop.data est souligné en rouge…
En remplacant le snapshop.data par un entier ca marche bien. Normalement mon future renvoie bien un entier… Bref je ne comprends pas d’où vient mon erreur.

le message d’erreur :

AsyncSnapshot<Object?> snapshot
Type: AsyncSnapshot<Object?>

The argument type 'Object?' can't be assigned to the parameter type 'int'.dartargument_type_not_assignable

Mets le code complet de ton futurBuilder stp, ainsi que celui de MonObjet.

Salur @Lugdu, voici mon code :

La home page, qui fonctionne quand je remplace le snapshot.data par un entier ou l’appel à un entier non « future » :

class _HomePageFutureState extends State<HomePageFuture> {
  late Future<int> _nbObjetsVoulus;

  @override
  void initState() {
    super.initState();
    _nbObjetVoulu = SettingsData.nbObjetVoulu();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return ObjetView(
              objetModel:
                 ObjetModel(nbObjet: snapshot.data));
        } else if (snapshot.hasError) {
          return Text("Loading error");
        } else {
          return CircularProgressIndicator();
        }
      },
      future: _nbObjetVoulu,
    );
  }
}

Le code de ObjetModel :

class ObjetModel {
  final int nbObjet;

 ObjetModel({required this.nbObjet});

  List<OtherObjetModel> _otherObjetList = [];

  // getter and computed properties
  List<OtherObjetModel> get otherObjetList {
    for (int i = 0; i <nbObjet; i++) {
      addOtherObjet();
// fonction qui ajoute un objet à ma liste qui fonctionne quand un entier arrive dans la boucle
    }
    return _otherObjetList;
  }

et dans mon ObjetView je construit un nombre de widjet en me basant sur le nombre d’objet dans la liste d’« otherObjet » de mon ObjetModel.

Bonjour,
Tu peux me mettre également le code de ton ObjetView. Et c’est quoi ce OtherObjetModel ?

Alors le OtherObjectModel c’est un « sous objet » de mon objet principal et je créé au sein de mon objet principal un nombre variable de sous objet otherObjetModel qui dispose aussi d’un Widget spécifique…

En gros le future qui doit renvoyer l’entier « nbObjet » permet de créer dans ma vue HomePage via une ListView ce nombre de OtherObjetView. J’aurai du l’appeler nbOtherObjet.

Quand je ne cherche pas à utiliser le future tout fonctionne bien. Et pour le ObjetView, je vais essayer de couper un peu le tout pour que ce soit plus facilement lisible avec ce qui est lié à ce fameux entier avec lequel je bagarre :

class ObjetView extends StatefulWidget {
  final ObjetModel objetModel;

  const ObjetView({
    super.key,
    required this.objetModel,
  });

  @override
  State<ObjetView> createState() => _ObjetViewState();
}

class _ObjetViewState extends State<ObjetView> {
  //Timer
  Timer? _timeView;
  final Duration _refreshTime = Duration(milliseconds: 10);

  //Variable
  final double _cacheExtent = 3100;

  List<OtherObjectView> get widgetOtherObjetList {
    List<OtherObjectView> _listToReturn = [];
    for (OtherObjectModel otherObjetModel in widget.objetModel.otherObjetList) {
      _listToReturn.add(OtherObjectView(otherObjetModel: otherObjetModel));
    }
    return _listToReturn;
  }

//ListView builder generate function
Widget _generateOtherObjet(BuildContext context, int numberLine) {
    return widgetOtherObjetList[numberLine];
  }

  @override
  void initState() {
    _timerView = Timer.periodic(
      _refreshTime,
      (timer) {
        setState(() {
          widget.objetModel.updateObjet();
        });
      },
    );
    super.initState();
  }

  @override
  void dispose() {
    _timerView!.cancel();
    _timerView = null;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    // some code....

            child: ListView.builder(
              itemBuilder: _generateOtherObjet,
              itemCount: widgetOtherObjetList.length,
              cacheExtent: _cacheExtent,
              scrollDirection: Axis.horizontal,
            ),

         // La fin du code
  }
}