I am new to Flutter so please bear with me. I have a paginated API that means on calling example.com?loaditems.php?page=0
will load first 10 items(podcasts list) and example.com?loaditems.php?page=1
will load items from 10 to 20 and so on.
I want StreamBuilder to fetch page 0 first then when the list reaches the bottom it should load page 1 and show it. To check if I have reached the last item in listview I am using ScrollController
of ListView.
Now I am using StreamBuilder, ListView, InheritedWidget in bloc pattern. I am not sure if I have implemented it correctly so I am gonna paste the entire code. My question is, is this is the correct BLOC pattern way to do it? If not then what is it? I also came across with this article: https://crossingthestreams.io/loading-paginated-data-with-list-views-in-flutter/ In the end it says "Update:" but I could not understand it much.
Here' the app's entry point:
void main() => runApp(new MaterialApp(
title: "XYZ",
theme: ThemeData(fontFamily: 'Lato'),
home: PodcastsProvider( //This is InheritedWidget
child: RecentPodcasts(), //This is the child of InheritedWidget
),
));
Here's the InheritedWidget PodcastsProvider:
class PodcastsProvider extends InheritedWidget{
final PodcastsBloc bloc; //THIS IS THE BLOC
PodcastsProvider({Key key, Widget child})
: bloc = PodcastsBloc(),
super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return true;
}
static PodcastsBloc of(BuildContext context){
return (context.inheritFromWidgetOfExactType(PodcastsProvider) as
PodcastsProvider).bloc;
}
}
Here's the Bloc
class PodcastsBloc{
var _podcasts = PublishSubject<List<Podcast>>();
Observable<List<Podcast>> get podcasts =>_podcasts.stream;
getPodcasts(pageCount) async{
NetworkProvider provider = NetworkProvider();
var podcasts = await provider.getRecentPodcasts(pageCount);
_podcasts.sink.add(podcasts);
}
despose(){
_podcasts.close();
}
}
Here's the view part (child of InheritedWidget)
class RecentPodcasts extends StatefulWidget {
@override
_RecentPodcastsState createState() => _RecentPodcastsState();
}
class _RecentPodcastsState extends State<RecentPodcasts> {
ScrollController controller = ScrollController();
PodcastsBloc podcastsBloc;
bool isLoading = false;
List<Podcast> podcasts;
@override
void didChangeDependencies() {
super.didChangeDependencies();
podcastsBloc = PodcastsProvider.of(context);
podcastsBloc.getPodcasts(null);
controller.addListener((){
if(controller.position.pixels == controller.position.maxScrollExtent && !isLoading){
setState(() {
isLoading = true;
podcastsBloc.getPodcasts(podcasts[podcasts.length-1].id);
});
}
}); //listerner ends
}
Finally, build method of _RecentPodcastsState calls this:
Widget getRecentPodcastsList(PodcastsBloc podcastsBloc) {
return StreamBuilder(
stream: podcastsBloc.podcasts,
builder: (context, snapshot) {
//isLoading = false;
if (snapshot.hasData) {
podcasts.addAll(snapshot.data); //THIS IS A PROBLEM, THIS GIVES ME AN ERROR: flutter: Tried calling: addAll(Instance(length:20) of '_GrowableList')
return ListView.builder(
scrollDirection: Axis.vertical,
padding: EdgeInsets.zero,
controller: controller,
itemCount: podcasts.length,
itemBuilder: (context, index) {
return RecentPodcastListItem(podcasts[index]);
});
} else if (snapshot.hasError) {
//SHOW ERROR TEXT
return Text("Error!");
} else {
//LOADER GOES HERE
return Text(
"Loading...",
style: TextStyle(color: Colors.white),
);
}
},
);
}}