When I run the code below, all I am getting now is.
I copied this code from another this post. This seems to work, prior to the last code I had, but I still am getting no success on retrieving any data. I tried the other things in the same post but I had no luck.
The method 'data' was called on null.
Receiver: null
Tried calling: data()
void main() {
runApp(myApp());
}
class myApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FirstRoute(title: 'First Route'),
);
}
}
class FirstRoute extends StatefulWidget {
FirstRoute({Key key, this.title}) : super(key: key);
final String title;
#override
_FirstRouteState createState() => _FirstRouteState();
}
class _FirstRouteState extends State<FirstRoute> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("test"),
),
body: FutureBuilder(
future: getData(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
children: [
Container(
height: 27,
child: Text(
"Name: ${snapshot.data.data()['Name']}",
overflow: TextOverflow.fade,
style: TextStyle(fontSize: 20),
),
),
],
);
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
));
}
Future<DocumentSnapshot> getData() async {
await Firebase.initializeApp();
return await FirebaseFirestore.instance
.collection("test")
.doc()
.get();
}
}
On the firestore website it says that there are some reads and there's also snapshots listeners active, but the error still persists.
Any recommendations and tips would be great. Thanks!
Related
I'm getting an error on my IOS simulator when I run my flutter app.
The offending widget is: FutureBuilder Build functions must never return null. To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "new Container(width: 0.0, height: 0.0)
void main(){
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Color(0xFF6A8D73),
primaryColorDark: Color(0xFF475E4D),
accentColor: Color(0xffCFE8D5),
primaryColorLight: Colors.white
),
home: FutureBuilder(
future: _initialization,
builder: (context, snapshot){
if (snapshot.hasError) {
print(snapshot.error);
return null;
}
if (snapshot.connectionState == ConnectionState.done) {
return HomePage();
}
return Splash();
},
)
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => UserRepository.instance(),
child: Consumer(
builder: (context, UserRepository user, _){
switch(user.status){
case Status.Uninitialized:
return Splash();
case Status.Unauthenticated:
case Status.Authenticating:
return LoginPage();
case Status.Authenticated:
return TaskBar();
default:
return null;
}
},
),
);
}
}
class Splash extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Text("Splash Screen"),
),
);
}
}
You just have to replace the following code where you are checking for error-
if (snapshot.hasError) {
print(snapshot.error);
return SizedBox();
}
[![enter image description here][1]][1]
I need to do it like this here:
[1]: https://i.stack.imgur.com/bNdZ3.png
But I can't do it. I tried some stuff but it doesn't work. Here is my main.dart below. I created the showImage method for showing image, I also applied it by Image.network(url); code but it didn't work,so I commented it.
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
var url;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void showImage() async {
final ref = FirebaseStorage.instance.ref().child('erkekyuz');
// no need of the file extension, the name will do fine.
url = await ref.getDownloadURL();
print(url);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot document) {
String mezunD;
if (document.data()['mezunDurumu'] == false) {
mezunD = "mezun değil";
}
if (document.data()['mezunDurumu'] == true) {
mezunD = "mezun değil";
}
var listTile = ListTile(
title: Column(
children: [
Expanded(
child: Text(
"Ad Soyad: " + document.data()['adSoyad'],
),
),
Expanded(
child: Text(
"Yaş: " + document.data()['yas'].toString(),
),
),
Expanded(
child: Text(
"Doğum Tarihi: " + document.data()['dogumTarihi'],
),
),
Expanded(
child: Text("Mezun Durumu: " + mezunD),
),
//Image.network(url),
//this didn't work somehow.
],
),
);
return listTile;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Öğrenci Durumu"),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('tablolar').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading...');
return ListView.builder(
itemExtent: 100.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_buildListItem(context, snapshot.data.documents[index]),
);
}),
);
}
}
Is your url variable showing any value?
Call your showImage() method like this to load image.
#override
void initState() {
super.initState();
showImage();
}
for showing images you can use :https://pub.dev/packages/cached_network_image
I'm trying to play a video from a URL of a Firestore Document. To play a video in Flutter, I have to instantiate its Url in the init() method. I set a default URL to a butterfly video, and the value was supposed to be replaced by the URL obtained from Firestore. (So that it is easy for me to see if the code works). However, the code does not work properly. I got an error that says "NoSuchMethodError: The getter 'value' was called on null".
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// Create the initialization Future outside of build
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
// Check for error
if (snapshot.hasError) {
print(snapshot.error);
return Center(
child: Container(
child: Text(
"Something went wrong",
textDirection: TextDirection.ltr,
),
),
);
}
//Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
return MaterialApp(
title: 'Flutter Demo',
home: VideoPlayerScreen(),
);
}
return CircularProgressIndicator();
});
}
}
class VideoPlayerScreen extends StatefulWidget {
#override
_VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
FirebaseFirestore firestore = FirebaseFirestore.instance;
String videoUrl =
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4';
#override
void initState() {
firestore.collection("videos").get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
// _controller.dispose();
videoUrl = doc["videoUrl"];
_controller = VideoPlayerController.network(videoUrl);
_initializeVideoPlayerFuture = _controller.initialize();
print(videoUrl);
})
});
// _controller = VideoPlayerController.network(videoUrl);
// _initializeVideoPlayerFuture = _controller.initialize();
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Video Player"),
),
body: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
children: [
AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
),
],
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}
Try the following:
#override
void initState() {
super.initState();
firestore.collection("videos").get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
videoUrl = doc["videoUrl"];
_controller = VideoPlayerController.network(videoUrl);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
});
});
}
Since initialize() is asynchronous, then you can use the method then which will get called when the future completes. Inside the callback, you can call setState() which will trigger a rebuild and notify the framework that the internal state of the widgets has changed .
https://pub.dev/packages/video_player
I updated to cloud_firestore 0.14.0
There's a few break changes:
BREAKING: The get data getter is now a data() method instead.
Before the update this is how I used the getter data
Before:
Future<String> getUsernameFromUserId(String userId) async {
return (await _userFirestoreCollection.document(userId).get()).data['screenName'];
}
This is how I use data now.. But doesn't seem to be working...
Now:
Future<String> getUsernameFromUserId(String userId) async {
return (await _userFirestoreCollection.document(userId).get()).data()['screenName'];
}
Starting from version cloud_firestore 0.14.0:
The method document() was changed and now you have to use doc() instead, therefore in your code you have to do the following:
Future<String> getUsernameFromUserId(String userId) async {
return (await _userFirestoreCollection.doc(userId).get()).data()["screenName"];
}
Example:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FirstRoute(title: 'First Route'),
);
}
}
class FirstRoute extends StatefulWidget {
FirstRoute({Key key, this.title}) : super(key: key);
final String title;
#override
_FirstRouteState createState() => _FirstRouteState();
}
class _FirstRouteState extends State<FirstRoute> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("test"),
),
body: FutureBuilder(
future: getData(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
children: [
Container(
height: 27,
child: Text(
"Name: ${snapshot.data.data()['name']}",
overflow: TextOverflow.fade,
style: TextStyle(fontSize: 20),
),
),
],
);
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
));
}
Future<DocumentSnapshot> getData() async {
await Firebase.initializeApp();
return await FirebaseFirestore.instance
.collection("users")
.doc("docID")
.get();
}
}
Hello
I'm trying to make my first social app with Flutter and I'm stuck.
I would like to get my messages (in a conversasion between tow users) from my api.
Not a probleme when I use Future and Future Builder, but I would like the message list to update when a new message is send !
I found we can achieve it with stream, but every time I try to convert my Future In Stream, it still work, but just as if it was a Future (it never upadate on new message).
here I a simplified part of my code :
class Test extends StatelessWidget {
final Conv conv;
final User otherUser;
const Test({Key key, this.conv, this.otherUser}) : super(key: key);
Stream<List<Message>> messageFlow(String convId) {
return Stream.fromFuture(getMessages(convId));
}
Future<List<Message>> getMessages(String convId) async {
var data = await http
.post(MyApiUrl, headers: <String, String>{}, body: <String, String>{
"someParam": "param",
"id": convId,
});
var jsonData = json.decode(data.body);
List<Message> messages = [];
for (var m in jsonData) {
Message message = Message.fromJson(m);
messages.add(message);
}
return messages;
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: messageFlow(conv.id),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text('Loading'),
),
);
}
return ListView.builder(
reverse: true,
controller: _messagesListController,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Message message = snapshot.data[index];
var isMe = message.owner == otherUser.id ? false : true;
return _buildMessage(message, isMe);
});
});
}
}
it would be so nice if you could help me !
I'm not able to replicate your sample code, but here how I understood your question.
Let's first define the difference about Future and Streams:
From this SO post
A Future is like the token with a number on it that they give you when
you order takeout; you made the request, but the result is not yet
ready but you have a placeholder. And when the result is ready, you
get a callback (the digital board above the takeout counter shows your
number or they shout it out) - you can now go in and grab your food
(the result) to take out.
A Stream is like that belt carrying little sushi bowls. By sitting
down at that table, you've "subscribed" to the stream. You don't know
when the next sushi boat will arrive - but when the chef (message
source) places it in the stream (belt), then the subscribers will
receive it. The important thing to note is that they arrive
asynchronously (you have no idea when the next boat/message will come)
but they will arrive in sequence (i.e., if the chef puts three types
of sushi on the belt, in some order -- you will see them come by you
in that same order)
Now here is an example of how you can create your own stream from scratch:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// 1st approach
final StreamController _streamController = StreamController();
addData()async{
for(int i = 1; i<= 10; i++) {
await Future.delayed(Duration(seconds: 1));
_streamController.sink.add(i);
}
}
// 2nd approach
// This approach will prevent some approach of memory leaks
Stream<int> numberStream() async*{
for(int i = 1; i<= 10; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
_streamController.close();
}
#override
void initState() {
// TODO: implement initState
super.initState();
addData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Stream"),
),
body: Center(
child: StreamBuilder(
stream: numberStream().map((number) => "number $number"),
builder: (context, snapshot){
if(snapshot.hasError)
return Text("hey there is some error");
else if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
return Text("${snapshot.data}", style: Theme.of(context).textTheme.display1,);
},
)
),
);
}
}
You can also check this SO post for some references.
Here, I tweaked the sample in the SO post above to create a mini simple chat server to show how the messages updates.
import 'dart:async';
import 'package:flutter/material.dart';
class Server {
StreamController<String> _controller = new StreamController.broadcast();
void simulateMessage(String message) {
_controller.add(message);
}
Stream get messages => _controller.stream;
}
final server = new Server();
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => new _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List<String> _messages = <String>[];
StreamSubscription<String> _subscription;
#override
void initState() {
_subscription = server.messages.listen((message) async => setState(() {
_messages.add(message);
}));
super.initState();
}
#override
void dispose() {
_subscription.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.display2;
return new Scaffold(
appBar: new AppBar(
title: new Text('Sample App'),
),
body: new ListView(
children: _messages.map((String message) {
return new Card(
child: new Container(
height: 100.0,
child: new Center(
child: new Text(message, style: textStyle),
),
),
);
}).toList(),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
new FloatingActionButton(
child: new Icon(Icons.account_circle_outlined),
onPressed: () {
// simulate a message arriving
server.simulateMessage('Hello World');
},
),
SizedBox(
height: 20.0,
),
new FloatingActionButton(
child: new Icon(Icons.account_circle_rounded),
onPressed: () {
// simulate a message arriving
server.simulateMessage('Hi Flutter');
},
),
],
),
);
}
}
class SampleApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomeScreen(),
);
}
}
void main() {
runApp(new SampleApp());
}
And here are some tutorials for better references:
https://www.youtube.com/watch?v=nQBpOIHE4eE
https://www.youtube.com/watch?v=OTS-ap9_aXc
this works for me
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as HTTP;
class PeriodicRequester extends StatelessWidget {
Stream<http.Response> getRandomNumberFact() async* {
yield* Stream.periodic(Duration(seconds: 5), (_) {
return http.get("http://numbersapi.com/random/");
}).asyncMap((event) async => await event);
}
#override
Widget build(BuildContext context) {
return StreamBuilder<http.Response>(
stream: getRandomNumberFact(),
builder: (context, snapshot) => snapshot.hasData
? Center(child: Text(snapshot.data.body))
: CircularProgressIndicator(),
);
}
}