dart 即使使用await关键字也不等待函数

neskvpey  于 2023-04-09  发布在  其他
关注(0)|答案(1)|浏览(119)

目前我有这个功能:

Future<void> savePictureToLocalStorage() async {
    // Obtenez le répertoire des documents de l'application
    Directory appDocDir = await getApplicationDocumentsDirectory();

    // Créez un fichier avec le nom de fichier souhaité dans le répertoire des documents de l'application
    File targetFile = File('${appDocDir.path}/$_imageFile');

    // Copiez le fichier source dans le fichier cible
    await _imageFile!.copy(targetFile.path);
    profile.profilePicture = targetFile.path;
  }

我把它叫做:

void saveAll(BuildContext context) async {
    String pseudo = nameController.text.trim();
    if (pseudo == "") {
      _showPopup(context);
    }

    if (imageChanged) {
      await savePictureToLocalStorage();
      await deleteImageIfLinkExists();
      await updateImageFirebase();
    }
    if (nameController.text != profile.nickname) {
      profile.nickname = nameController.text;
      updateNameFirebase();
    }
    await UserProfile.saveProfileIntoMemory();
  }

我希望savePictureToLocalStorage()在saveAll函数结束之前完成。
然而事实并非如此。其他函数只是在savePictureToLocalStorage()完成之前继续运行。
对于上下文:
我有阶级联系

import 'dart:io';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:jukebox/screens/update_account_case.dart';
import 'package:jukebox/utils/ElevatedButtonImpl.dart';
import '../backend/music_platform.dart';
import '../backend/user_profile.dart';
import '../utils/globals.dart' as globals;

class Connexion extends StatefulWidget {
  const Connexion({super.key});

  @override
  State<Connexion> createState() => ConnexionState();
}

class ConnexionState extends State<Connexion> {
  final textController = TextEditingController();
  Image? _profilePicture;

  ConnexionState() {
    _init();
  }

  /// This function is used to initialize the user profile
  Future _init() async {
    final UserProfile profile = UserProfile.instance;
    textController.text = profile.nickname;
    _profilePicture = profile.profilePicture == 'default'
        ? Image.asset('images/default_profile_picture.png')
        : Image.asset(profile.profilePicture);
    DocumentSnapshot userSnapshot = await FirebaseFirestore.instance
        .collection('User')
        .doc(profile.userId)
        .get();
    if (!userSnapshot.exists) {
      createUserFirebase(profile);
    }
  }

  createUserFirebase(UserProfile userProfile) async {
    var collection = FirebaseFirestore.instance.collection('User');
    collection.doc(userProfile.userId).set({
      'name': userProfile.nickname,
      'profile_picture': userProfile.profilePicture,
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBody: true,
      resizeToAvoidBottomInset: true,
      extendBodyBehindAppBar: true,
      bottomNavigationBar: ElevatedButtonImpl(
        onPressed: () async {
          await Navigator.of(context).push(MaterialPageRoute(
            builder: (BuildContext context) {
              return UpdateAccountInfo(profilePicture: _profilePicture);
            },
            fullscreenDialog: true,
          ));
          setState(() {
            textController.text = UserProfile.instance.nickname;
            _profilePicture = UserProfile.instance.profilePicture == 'default'
                ? Image.asset(globals.defaultPicture)
                : Image.asset(UserProfile.instance.profilePicture);
          });
        },
        text: "Modifier",
      ),
      body: Container(
        height: double.infinity,
        width: double.infinity,
        decoration: const BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.bottomLeft,
            end: Alignment.topRight,
            colors: [
              Color.fromRGBO(125, 70, 151, 1),
              Color.fromRGBO(255, 0, 157, 1),
            ],
          ),
        ),
        child: Center(
          child: SizedBox(
            width: 350,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                _profilePicture == null
                    ? const CircleAvatar(
                        radius: 120,
                        backgroundImage: AssetImage('images/camera.png'),
                      )
                    : CircleAvatar(
                        radius: 120,
                        backgroundImage: _profilePicture!.image,
                      ),
                TextField(
                  controller: textController,
                  autofocus: false,
                  scrollPadding: const EdgeInsets.only(bottom: 300),
                  cursorColor: const Color.fromRGBO(233, 165, 208, 1),
                  maxLength: 15,
                  textAlign: TextAlign.center,
                  style: const TextStyle(
                      color: Color.fromRGBO(233, 165, 208, 0.9), fontSize: 40),
                  decoration: const InputDecoration(counterText: ""),
                  readOnly: true,
                ),
                //PLATFORMS
                for (var platform in MusicPlatform.values)
                  PlatformButton(musicPlatform: platform),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class PlatformButton extends StatelessWidget {
  final MusicPlatform musicPlatform;

  const PlatformButton({Key? key, required this.musicPlatform})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.only(bottom: 10, right: 0, top: 10, left: 0),
      child: ElevatedButton(
        style: ButtonStyle(
          padding: const MaterialStatePropertyAll(EdgeInsets.all(0)),
          shape: MaterialStatePropertyAll(
            RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
          ),
        ),
        onPressed: () {},
        child: Row(
          children: [
            // ignore: sized_box_for_whitespace
            Container(
              height: 40,
              width: 39,
              child: const Card(
                color: Colors.blue,
              ),
            ),
            const SizedBox(
              width: 10,
            ),
            Text(
              musicPlatform.platformName,
              style: const TextStyle(
                color: Color.fromRGBO(255, 0, 157, 1),
              ),
            ),
            const Expanded(
              child: Card(),
            ),
            IconButton(
              iconSize: 40,
              onPressed: () {},
              icon: const Icon(
                Icons.check_outlined,
                color: Color.fromRGBO(255, 0, 157, 1),
              ),
            )
          ],
        ),
      ),
    );
  }
}

在小部件ElevatedButtonImpl的onPressed属性中,我调用类UpdateAccountInfo。
它调用下面的UpdateAccountInfo类:

import 'dart:io';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:jukebox/utils/ContainerImpl.dart';
import 'package:jukebox/utils/ElevatedButtonImpl.dart';
import 'package:path_provider/path_provider.dart';
import '../backend/user_profile.dart';
import 'package:path/path.dart';
import '../utils/globals.dart' as globals;

class UpdateAccountInfo extends StatefulWidget {
  final Image? profilePicture;

  const UpdateAccountInfo({Key? key, required this.profilePicture})
      : super(key: key);

  @override
  State<UpdateAccountInfo> createState() => _UpdateAccountInfo();
}

class _UpdateAccountInfo extends State<UpdateAccountInfo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(globals.majInfo),
        backgroundColor: const Color.fromRGBO(255, 0, 157, 1),
      ),
      body: Center(
        child: Form(profilePicture: widget.profilePicture),
      ),
    );
  }
}

class Form extends StatefulWidget {
  Image? profilePicture;

  Form({Key? key, required this.profilePicture}) : super(key: key);

  @override
  State<Form> createState() => _Form();
}

class _Form extends State<Form> {
  File? _imageFile;
  final FirebaseStorage _storage = FirebaseStorage.instance;
  final nameController = TextEditingController();
  final UserProfile profile = UserProfile.instance;
  bool imageChanged = false;
  bool nameChanged = false;

  _Form() {
    _init();
  }

  Future _init() async {
    final UserProfile profile = UserProfile.instance;
    nameController.text = profile.nickname;
  }

  Future _pickImage(ImageSource source) async {
    try {
      final image = await ImagePicker().pickImage(source: source);
      if (image == null) return;
      _imageFile = File(image.path);
      setState(() {
        widget.profilePicture = Image.file(_imageFile!);
      });
    } on Exception catch (e) {
      // ignore: avoid_print
      print(e);
      Navigator.of(context as BuildContext).pop();
    }
  }

  Future<void> deleteImageIfLinkExists() async {
    // Récupérer le lien actuel depuis la table
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    DocumentSnapshot userSnapshot =
        await firestore.collection('User').doc(profile.userId).get();

    Map<String, dynamic> userData = userSnapshot.data() as Map<String, dynamic>;
    String profilePicture = userData['profile_picture'];

    // Vérifier si le lien est non null et non vide
    if (profilePicture != 'default') {
      // Créer une référence au fichier dans Firebase Storage
      Reference ref = FirebaseStorage.instance.refFromURL(profilePicture);

      // Supprimer le fichier du Firebase Storage
      try {
        await ref.delete();
      } catch (e) {
        // Gérer les erreurs de suppression de fichier ici
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return ContainerImpl(
        child: SingleChildScrollView(
      child: Column(
        children: [
          const SizedBox(
            height: 20,
          ),
          const SizedBox(
            height: 20,
          ),
          CircleAvatar(
            radius: 120,
            backgroundImage: widget.profilePicture!.image,
          ),
          const SizedBox(
            height: 20,
          ),
          ElevatedButtonImpl(
              onPressed: () {
                _pickImage(ImageSource.gallery);
                imageChanged = true;
              },
              text: "Importer une photo"),
          const SizedBox(
            height: 20,
          ),
          TextField(
            controller: nameController,
            autofocus: false,
            scrollPadding: const EdgeInsets.only(bottom: 300),
            cursorColor: const Color.fromRGBO(233, 165, 208, 1),
            maxLength: 15,
            textAlign: TextAlign.center,
            style: const TextStyle(
                color: Color.fromRGBO(233, 165, 208, 0.9), fontSize: 40),
            decoration: const InputDecoration(counterText: ""),
          ),
          const SizedBox(
            height: 80,
          ),
          Row(
            children: [
              Expanded(
                  child: ElevatedButtonImpl(
                      onPressed: () {
                        saveAll(context);
                        Navigator.pop(context);
                      },
                      text: "Enregistrer"))
            ],
          )
        ],
      ),
    ));
  }

  void _showPopup(BuildContext context) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Pseudo vide'),
          content: const Text('Veuillez renseigner un pseudo'),
          actions: <Widget>[
            TextButton(
              child: const Text('OK'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  void saveAll(BuildContext context) async {
    String pseudo = nameController.text.trim();
    if (pseudo == "") {
      _showPopup(context);
    }

    if (imageChanged) {
      await savePictureToLocalStorage();
      await deleteImageIfLinkExists();
      await updateImageFirebase();
    }
    if (nameController.text != profile.nickname) {
      profile.nickname = nameController.text;
      updateNameFirebase();
    }
    await UserProfile.saveProfileIntoMemory();
  }

  Future<void> updateImageFirebase() async {
    String profilePicture = profile.profilePicture;
    Reference ref = _storage.ref("profile_pictures");
    UploadTask uploadTask = ref.putFile(_imageFile!);

    // Attendez la fin de l'UploadTask
    TaskSnapshot snapshot = await uploadTask;

    // Récupérez l'URL de téléchargement
    profilePicture = await snapshot.ref.getDownloadURL();

    // Mettez à jour la base de données
    var collection = FirebaseFirestore.instance.collection('User');
    await collection
        .doc(profile.userId)
        .update({'profile_picture': profilePicture, 'name': profile.nickname});

    // Mettez à jour l'objet profile
    profile.profilePicture = profilePicture;
  }

  void updateNameFirebase() {
    var collection = FirebaseFirestore.instance.collection('User');
    collection.doc(profile.userId).update({'name': nameController.text});
  }

  Future<void> savePictureToLocalStorage() async {
    // Obtenez le répertoire des documents de l'application
    Directory appDocDir = await getApplicationDocumentsDirectory();

    // Créez un fichier avec le nom de fichier souhaité dans le répertoire des documents de l'application
    File targetFile = File('${appDocDir.path}/$_imageFile');

    // Copiez le fichier source dans le fichier cible
    await _imageFile!.copy(targetFile.path);
    profile.profilePicture = targetFile.path;
  }
}

如果你发现了窍门,提前谢谢你。
我试着把等待几乎无处不在。

eqqqjvef

eqqqjvef1#

将void函数转换为Future<void>

Future<void> saveAll(BuildContext context) async {
    String pseudo = nameController.text.trim();
.....

等着完成它。

child: ElevatedButtonImpl(
     onPressed: () async{
        await saveAll(context); //the void function dont/cant await, therefore you need to convert it to the Future
        Navigator.pop(context);
      },
     text: "Enregistrer")

相关问题