I almost tried everything. My functions async, my snapshots async. I'm using future builders, My carousel slider works fine. I don't need to hot reload or refresh for carousel slider. But for my listview builder i need to refresh every time to fetch data. I tried connection state status for if statment but connection state getting done quickly (before data completely loaded). So my pictures and my datas not coming without refresh or hot reload.
import 'package:cached_network_image/cached_network_image.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:video_games/model.dart';
import 'package:flutter/material.dart';
import 'package:video_games/send_models.dart';
import 'package:video_games/views/details_view.dart';
import 'package:get/get.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
class HomePage extends StatefulWidget {
HomePage({
Key? key,
}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Future<Autogenerated> apiCall() async {
final response = await http.get(Uri.parse(
'https://api.rawg.io/api/games?key=5ac29048d12d45d0949c77038115cb56&page=1'));
return Autogenerated.fromJson(jsonDecode(response.body));
}
int slideractiveindex = 0;
var urlImages = [];
var uniqueImages = [];
var growableList = [];
var listId = [];
@override
Widget build(BuildContext context) {
clearCache();
return SingleChildScrollView(
child: Column(
children: [
FutureBuilder<Autogenerated>(
future: apiCall(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<Results>? data = snapshot.data!.results;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CarouselSlider.builder(
itemCount: 20,
itemBuilder: (context, index, realIndex) {
urlImages.add(data![index].backgroundImage);
uniqueImages = urlImages.toSet().toList();
final urlImage = uniqueImages[index];
return buildImage(urlImage, index);
},
options: CarouselOptions(
autoPlay: true,
enlargeCenterPage: true,
onPageChanged: (index, reason) {}),
),
const SizedBox(height: 32),
],
);
},
),
FutureBuilder<Autogenerated>(
future: apiCall(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
print(snapshot.connectionState);
print(urlImages.length);
List<Results>? data = snapshot.data!.results;
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, index) {
growableList.add(data![index].name);
listId.assign(data[index].id);
// String? id = data[index].id.toString();
// urlImages.add(data[index].backgroundImage);
uniqueImages = urlImages.toSet().toList();
final urlImage = uniqueImages[index 1];
return Padding(
padding: const EdgeInsets.all(10.0),
child: ListTile(
tileColor: Colors.black12,
leading: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsPage(
id: '${data[index].id}',
),
));
},
child: buildImage2(urlImage, index)),
title: Column(
children: [
Text(
'${data[index].name}',
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Rating : ${data[index].rating}'),
SizedBox(
width: 20,
),
Text('Release : ${data[index].released}'),
],
)
],
),
),
);
},
itemCount: 19,
);
} else {
return CircularProgressIndicator();
}
},
),
],
),
);
}
Widget buildImage(String? urlImage, int index) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 12),
color: Colors.grey,
child: CachedNetworkImage(
imageUrl: urlImage!,
fit: BoxFit.cover,
key: UniqueKey(),
errorWidget: (context, url, error) => Icon(Icons.error),
placeholder: (context, url) => Container(
child: Center(
child: CircularProgressIndicator(),
),
),
));
}
Widget buildImage2(String? urlImage, int index) {
return Container(
height: 100,
width: 100,
child: CachedNetworkImage(
imageUrl: urlImage!,
key: UniqueKey(),
fit: BoxFit.cover,
errorWidget: (context, url, error) => Icon(Icons.error),
placeholder: (context, url) => Container(
child: Center(
child: CircularProgressIndicator(),
),
),
));
}
void clearCache() {
DefaultCacheManager().emptyCache();
imageCache!.clear();
imageCache!.clearLiveImages();
setState(() {});
}
}
This is my error part
════════ Exception caught by widgets library ═══════════════════════════════════
RangeError (index): Invalid value: Valid value range is empty: 17
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
RangeError (index): Invalid value: Valid value range is empty: 18
════════════════════════════════════════════════════════════════════════════════
CodePudding user response:
FutureBuilder
removes boilerplate code. see
Let's say you want to fetch some data from the backend on page launch and show a loader until data comes.
Tasks for ListBuilder:
Have two state variables,
dataFromBackend
andisLoadingFlag On
launch, set
isLoadingFlag = true
, and based on this, showloader
.Once data arrives, set data with what you get from backend and set
isLoadingFlag = false
(insidesetState
obviously)We need to have a
if-else
in widget creation. IfisLoadingFlag
istrue
,show theloader
else show thedata
. On failure, show error message.
Tasks for FutureBuilder:
- Give the async task in
future
of Future Builder - Based on
connectionState
, show message (loading,active(streams)
,done
) - Based on
data(snapshot.hasError)
, show view
Pros of FutureBuilder
- Does not use the two state variables and setState
- Reactive programming (FutureBuilder will take care of updating the view on data arrival)
Example:
FutureBuilder<String>(
future: _fetchNetworkCall, // async work
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return Text('Loading....');
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
return Text('Result: ${snapshot.data}');
}
},
)