Reputation: 175
I was wondering if someone could show me how to implement the Flutter StreamProvider "catchError" property?
Example code below to add to:
StreamProvider<LocationModelNormal>.value(
initialData: LocationModelNormal.initialData(),
stream: locationStreamInstance.specificLocation(_secondWonder),
catchError: ?????????
),
class LocationModelNormal {
final String name;
LocationModelNormal({
this.name
});
factory LocationModelNormal.fromMap(Map<String, dynamic> data) {
return LocationModelNormal(
name: data['name'] ?? '',
);
}
factory LocationModelNormal.initialData() {
return LocationModelNormal(
name: '',
);
}
}
Upvotes: 7
Views: 4370
Reputation: 2013
Remi of course has the most thorough and proper method, since in the case of an error, you need to provide a value in its place or make it nullable. His solution is the most complete.
However, if you have other things already established, and need a down and dirty solution: Below I make it nullable with the ? and return a null value in the case of an error. The return is not technically necessary.
StreamProvider<LocationModelNormal?>.value(
initialData: LocationModelNormal.initialData(), //or null maybe better
stream: locationStreamInstance.specificLocation(_secondWonder),
catchError: (context, e) {
print('error in LocationModelNormal: ${e.toString()}');
//or pop a dialogue...whatever.
return null;
},
),
Upvotes: 0
Reputation: 785
Easy fix for now.
@override
Widget build(BuildContext context) {
return StreamProvider<UserModel?>.value(
value: AuthenticationService().user,
initialData: null,
catchError: (_, err) => null,
child: const MaterialApp(
home: AuthWrapper(),
),
);
}
}
Upvotes: 0
Reputation: 3164
You can also do this
StreamProvider<DocumentSnapshot>.value(
value: api.myDetails(mail),
child: Builder(
builder: (context){
var snapshot = Provider.of<DocumentSnapshot>(context);
if(snapshot == null){
return customF.loadingWidget();
}else{
return Stack(
children: <Widget>[
getMainListViewUI(),
getAppBarUI(),
SizedBox(
height: MediaQuery.of(context).padding.bottom,
)
],
);
}
}
),
),
Upvotes: -1
Reputation: 276957
You'll want to model your data using sealed classes:
abstract class Data {}
class Content implements Data {
Content(this.data);
final List<String> data;
}
class Error implements Data {
Error(this.msg);
final String msg;
}
class Loading implements Data {
const Loading();
}
Then used like so in the provider:
StreamProvider<Data>(
builder: (_) async* {
yield Content(['hello', 'world']);
},
initialData: const Loading(),
catchError: (_, err) => Error(err.toString()),
child: Container(),
);
And consumed as such:
Consumer<Data>(
builder: (_, data, __) {
if (data is Loading) {
return const CircularProgressIndicator();
} else if (data is Error) {
return Center(child: Text(data.msg));
} else if (data is Content) {
return ListView.builder(
itemCount: data.data.length,
itemBuilder: (_, index) => Text(data.data[index]),
);
}
throw FallThroughError();
},
);
Upvotes: 18