HeWantedIndigo
HeWantedIndigo

Reputation: 23

Can't add Url of Firebase Storage Image to Realtime Database

In this app, I click a picture either by a camera or upload from Gallery and pass it to a provider. I want to upload that image to Firebase Storage and then store its Image Url in a realtime database with some other String and double type information. But I can't seem to do that as the data seems to get uploaded in the realtime database before the image url can be processed. The image is still uploaded in the storage properly. Here is the code for my Provider class.

The concerned methods are uploadPic() and addPlace()

import 'dart:io';
import 'dart:convert';
import 'package:path/path.dart' as Path;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:firebase_storage/firebase_storage.dart';
import '../models/place.dart';

class MyPlaces with ChangeNotifier {

  List<Place> _places = [];

  List<Place> get places {
    return [..._places];
  }

  Future<void> fetchAndSetPlaces() async {
    const url = 'my firebase url';
    try {
      final response = await http.get(url);
      final extractedData = json.decode(response.body) as Map<String,dynamic>;
      final List<Place> loadedPlaces = [];
      extractedData.forEach((id, data) {
        loadedPlaces.add(Place(
          id: id,
          cropName: data['cropName'],
          imageUrl: data['imageUrl'],
          location: Location(
            latitude: data['latitude'],
            longitude: data['longitude'],
            //address: data['address'],
          ),
        ));
        _places = loadedPlaces;
        notifyListeners();
      });
    } catch(error) {
      throw error;
    }
  }

  Future<void> addPlace(String cropName, File image, Location loc) async {
    const url = 'my firebase url';
    String imageUrl;
    await uploadPic(image, imageUrl);
    try {
      final response = await http.post(url, body: json.encode({
        'cropName' : cropName,
        'imageUrl' : imageUrl,
        'latitude' : loc.latitude,
        'longitude' : loc.longitude,
      }));
      final newPlace = Place(
      id: json.decode(response.body)['name'],
      cropName: cropName,
      imageUrl: imageUrl,
      location: loc,
    );
      _places.add(newPlace);
      notifyListeners();
    } catch (error) {
      throw error;
    }


  }

  Place findPlaceById(String id) {
    return _places.firstWhere((place) => place.id == id);
  }

  Future uploadPic(pickedImage, imageUrl) async {
      StorageReference firebaseStorageRef = FirebaseStorage.instance.ref().child('chats/${Path.basename(pickedImage.path)}}');
      StorageUploadTask uploadTask = firebaseStorageRef.putFile(pickedImage);
      await uploadTask.onComplete;
      print("File uploaded!");
      firebaseStorageRef.getDownloadURL().then((fileUrl) {
        imageUrl = fileUrl;
      });
      notifyListeners();
  }

}

I'm calling the addplace() method in a form page in the submitForm() method.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../models/place.dart';
import '../providers/my_places.dart';
import '../widgets/image_input.dart';
import '../widgets/location_input.dart';
import '../widgets/custom_drawer.dart';
import '../screens/my_geo_tags_screen.dart';

class AddNewPlaceScreen extends StatefulWidget {

  static const routeName = '/add_new_place_screen';

  @override
  _AddNewPlaceScreenState createState() => _AddNewPlaceScreenState();
}

class _AddNewPlaceScreenState extends State<AddNewPlaceScreen> {

  Place currentPlace;

  final _cropNameController = TextEditingController();
  File _pickedImage;
  Location _pickedLocation;

  void selectImage(File image) {
    setState(() {
      _pickedImage = image;
    });
  }

  void selectLocation(double lat, double long) {
    _pickedLocation = Location(
      latitude: lat,
      longitude: long,
    );
  }



  void _submitForm() {
    if (_cropNameController.text == null || _pickedImage == null || _pickedLocation == null) {
      return;
    }
    Provider.of<MyPlaces>(context).addPlace(_cropNameController.text, _pickedImage, _pickedLocation);
    Navigator.of(context).pop();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Add new Geo Tag", style: Theme.of(context).textTheme.title),
        iconTheme: IconThemeData(color: Colors.amber),
      ),
      drawer: CustomDrawer(),
      body: SingleChildScrollView(
        child: Container(
          padding: EdgeInsets.all(20),
          child: Column(
            children: <Widget>[
              TextField(
                style: TextStyle(
                  color: Theme.of(context).primaryColor,
                ),
                decoration: InputDecoration(
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(5),
                  ),
                  labelText: "Name of the crop",
                  labelStyle: TextStyle(
                    color: Theme.of(context).primaryColor,
                  ),
                ),
                controller: _cropNameController,
              ),
              SizedBox(height: 15),
              ImageInput(selectImage),
              SizedBox(height: 15),
              LocationInput(selectLocation),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Theme.of(context).accentColor,
        child: Icon(
          Icons.save,
          color: Theme.of(context).primaryColor,
        ),
        onPressed: () {
          _submitForm();
          Navigator.of(context).pushReplacementNamed(MyGeoTagsScreen.routeName);
        },
      ),
    );
  }
}

Upvotes: 0

Views: 327

Answers (1)

GrahamD
GrahamD

Reputation: 3165

I think you need to await firebaseStorageRef.getDownloadURL().then((fileUrl) { in Future uploadPic. Mixing await and .then can lead to issues though, I believe. So try removing the .then and simply execute this statement imageUrl = await firebaseStorageRef.getDownloadURL();

Upvotes: 2

Related Questions