i want to get data from open weather api, and i keep getting this:
NoSuchMethodError: The method '[]' was called on null.Reciever: null
tried calling:
is it a problem with the api or the code?the editor don't show any errors please help
my code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(MaterialApp(
title: 'Weather',
home: Weather(),
));
}
String api_key = 'the key';
Future<List> fetchData() async {
var result = await http.get(Uri.http('http://api.openweathermap.org',
'weather?lat=15.53804515&lon=32.52674103&appid=$api_key&units=metric'));
return json.decode(result.body);
}
class Weather extends StatefulWidget {
#override
_WeatherState createState() => _WeatherState();
}
class _WeatherState extends State<Weather> {
Color bgcolor;
var data;
#override
void initState() {
super.initState();
fetchData().then((value) {
setState() {
data = value;
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
appBar: AppBar(
title: Text('Weather App'),
centerTitle: true,
),
body: Center(
child: Column(children: [
Text(data['main']['temp']),
Text(data['weather']['description']),
Text(data['name'])
]),
));
}
}
fetchData is asynchronous, meaning it will take some time to execute and fetch that weather data. Until then, the variable "data" is uninitialized and thus null. Try adding a check for if data is null, then return a loading page or CircularProgressIndicator.
Just add a simple null check -
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(MaterialApp(
title: 'Weather',
home: Weather(),
));
}
String api_key = 'the key';
Future<List> fetchData() async {
var result = await http.get(Uri.http('http://api.openweathermap.org',
'weather?lat=15.53804515&lon=32.52674103&appid=$api_key&units=metric'));
return json.decode(result.body);
}
class Weather extends StatefulWidget {
#override
_WeatherState createState() => _WeatherState();
}
class _WeatherState extends State<Weather> {
Color bgcolor;
var data;
#override
void initState() {
super.initState();
fetchData().then((value) {
setState() {
data = value;
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
appBar: AppBar(
title: Text('Weather App'),
centerTitle: true,
),
body: Center(
child: data == null
? CircularProgressIndicator()
: Column(children: [
Text(data['main']['temp']),
Text(data['weather']['description']),
Text(data['name'])
]),
));
}
}
Related
I have a serious problem with my Riverpod. Specifically, I am using StateProvider in Riverpod package. But when I update state, the widget tree does not rebuild. I checked the new state whether is updated by printing out state to see, I see that they are actually updated.
I have some same situations but when I click hot restart/reload page/scroll up,down mouse to change size chrome window, the widget tree rebuild one time.
Please help me and explain everything the most detail and easy to understand. Thank you very much
new state print out but UI not update
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:math';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class Data {
final String data;
Data({required this.data});
}
final helloWorldProvider = StateProvider<Data?>((ref) => Data(data: 'No data'));
class MyApp extends ConsumerStatefulWidget {
const MyApp({super.key});
#override
ConsumerState<MyApp> createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> {
#override
void initState() {
// TODO: implement initState4
print("Init state");
super.initState();
// getData();
}
// getData() async {
// // http.Response response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1'));
// // final title = jsonDecode(response.body)["title"];;
// // ref.read(helloWorldProvider.notifier).update((state) => title);
// SharedPreferences prefs = await SharedPreferences.getInstance();
// prefs.setString('valueTemp', 'newValue');
// String? valueTemp = prefs.getString('valueTemp');
// String value = valueTemp ?? '';
// Data data = Data(data: value);
// ref.read(helloWorldProvider.notifier).update((state) => data);
// print("Đã thực hiện xong");
// }
void _change() {
print("change");
final rawString = generateRandomString(5);
Data data = new Data(data: rawString);
ref.watch(helloWorldProvider.notifier).update((state) => data);
print(ref.read(helloWorldProvider.notifier).state?.data);
}
String generateRandomString(int len) {
var r = Random();
return String.fromCharCodes(List.generate(len, (index) => r.nextInt(33) + 89));
}
#override
Widget build(BuildContext context) {
print('Rebuild');
final data = ref.watch(helloWorldProvider.notifier).state;
final dataText = data?.data ?? 'No text';
print(dataText);
return MaterialApp(
title: 'Google Docs Clone',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Center(
child: Column(children: [
Text(dataText)
]
)
),
floatingActionButton: FloatingActionButton(
onPressed: _change,
tooltip: 'Change',
child: const Icon(Icons.add),
),
));
}
}
I don't want to use other pattern as Provider, Bloc, StateNotifierProvider, ChangeNotifierProvider... I only want to run StateProvider successfully. I have refered to many articles and stackoverflows answer but I did't found any useful helps to my case.
final data = ref.watch(helloWorldProvider.notifier).state;
is watching the notifier, which rarely changes. You want to watch the state change, as in:
final data = ref.watch(helloWorldProvider);
Fixed, Tested your code.
I recommend this article Flutter Riverpod 2.0: The Ultimate Guide to Advanced Riverpod 😀
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:math';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class Data {
final String data;
Data({required this.data});
}
final helloWorldProvider = StateProvider<Data?>((ref) => Data(data: 'No data'));
class MyApp extends ConsumerStatefulWidget {
const MyApp({super.key});
#override
ConsumerState<MyApp> createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> {
#override
void initState() {
// TODO: implement initState4
print("Init state");
super.initState();
// getData();
}
// getData() async {
// // http.Response response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1'));
// // final title = jsonDecode(response.body)["title"];;
// // ref.read(helloWorldProvider.notifier).update((state) => title);
// SharedPreferences prefs = await SharedPreferences.getInstance();
// prefs.setString('valueTemp', 'newValue');
// String? valueTemp = prefs.getString('valueTemp');
// String value = valueTemp ?? '';
// Data data = Data(data: value);
// ref.read(helloWorldProvider.notifier).update((state) => data);
// print("Đã thực hiện xong");
// }
void _change() {
print("change");
final rawString = generateRandomString(5);
Data data = Data(data: rawString);
ref.read(helloWorldProvider.notifier).update((state) => data);
print(ref.read(helloWorldProvider.notifier).state?.data);
}
String generateRandomString(int len) {
var r = Random();
return String.fromCharCodes(
List.generate(len, (index) => r.nextInt(33) + 89));
}
#override
Widget build(BuildContext context) {
print('Rebuild');
final data = ref.watch(helloWorldProvider)?.data;
final dataText = data ?? 'No text';
print(dataText);
return MaterialApp(
title: 'Google Docs Clone',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Center(
child: Column(children: [Text(dataText)]),
),
floatingActionButton: FloatingActionButton(
onPressed: _change,
tooltip: 'Change',
child: const Icon(Icons.add),
),
),
);
}
}
Isar does not persist state, every time I close my mobile application and open it again, previous values are not there, when they should be there. I'm fetching those values from Isar.
Please show with a counter app example how this works.
I'm attaching files.
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isarapp/counter_schema.dart';
import 'package:isar/isar.dart';
import 'package:isarapp/home_screen.dart';
import 'package:path_provider/path_provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
var directory = await getApplicationDocumentsDirectory();
var path = directory.path;
await Isar.open(
[CounterObjectSchema],
directory: path,
inspector: true,
name: "isardb",
);
runApp(const MyApp());
}
class MyApp extends ConsumerWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context, WidgetRef ref) {
return ProviderScope(
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomeScreen(),
),
);
}
}
I have edited android manifest file to get store permission then using permission_handler for getting storage access.
home_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar/isar.dart';
import 'package:isarapp/counter_schema.dart';
import 'package:permission_handler/permission_handler.dart';
final counterProvider1 = StateProvider<int>((ref) {
return 0;
});
class HomeScreen extends ConsumerStatefulWidget {
const HomeScreen({super.key});
#override
ConsumerState<ConsumerStatefulWidget> createState() => _HomeScreenState();
}
getStoragePermission() async {
var status = await Permission.storage.status;
if (status.isDenied) {
Permission.storage.request();
}
}
class _HomeScreenState extends ConsumerState<HomeScreen> {
Isar? isar = Isar.getInstance("isardb");
CounterObject counterObject = CounterObject(counter: 9);
initCounter() async {
var count = await isar?.collection<CounterObject>().get(counterObject.id);
//reset counter on launch
ref.read(counterProvider1.notifier).state = count?.counter ?? -1;
}
increment() async {
counterObject.counter = counterObject.counter + 1;
//update state
ref.read(counterProvider1.notifier).state = counterObject.counter;
//writing counterValue to isardb on every increment call
isar?.writeTxn(
() async => await isar?.collection<CounterObject>().put(counterObject),
);
}//increment
#override
void initState() {
getStoragePermission();
//putting counterObject in
isar?.writeTxn(
() async => await isar?.counterObjects.put(counterObject),
);
initCounter();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
Text(
ref.watch(counterProvider1).toString(),
style: const TextStyle(fontSize: 54),
),
GestureDetector(
onTap: () => increment(),
child: Container(
width: 200,
height: 40,
color: Colors.blue[300],
child: const Center(child: Text("Add")),
),
),
],
),
),
),
);
}
}
CounterObjectSchema
import 'package:isar/isar.dart';
part 'counter_schema.g.dart';
#collection
class CounterObject {
Id id = Isar.autoIncrement;
int counter;
CounterObject({required this.counter});
}
I am trying to use the BLoC library with the connectivity_plus plugin in Flutter. I have followed this post and this post to set up an Internet Cubit for the project. The code works fine when the app is started with the internet connection turned on.
However, with the internet connection turned off, if I kill the app and re-launch it or do a hot restart, the CircularProgressIndicator() is shown instead of Text("Internet Disconnected").
Turning the internet back on correctly shows Text("Internet Connected") widget. After this, If I turn off the internet connection again, this time around it correctly shows the Text("Internet Disconnected") widget.
Also, emitInternetDisconnected is not caught as an exception in the try catch block to update the app's state.
The problem with the CircularProgressIndicator() being always displayed with the internet disconnected occurs only when the app is re-launched or hot restarted. I cannot figure out the bug in my code. What should I do to fix my code? Thanks
This is the code in the internet_cubit.dart file
import 'dart:async';
import 'dart:io';
import 'package:bloc/bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'internet_enum.dart';
part 'internet_state.dart';
class InternetCubit extends Cubit<InternetState> {
final Connectivity? connectivity;
StreamSubscription? connectivityStreamSubscription;
InternetCubit({required this.connectivity}) : super(InternetLoading()) {
monitorInternetConnection();
}
void monitorInternetConnection() async {
connectivityStreamSubscription =
connectivity!.onConnectivityChanged.listen((connectivityResult) async {
try {
final result = await InternetAddress.lookup("example.com");
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
if (connectivityResult == ConnectivityResult.wifi) {
emitInternetConnected(ConnectionType.WiFi);
} else if (connectivityResult == ConnectivityResult.mobile) {
emitInternetConnected(ConnectionType.Mobile);
} else if (connectivityResult == ConnectivityResult.none) {
emitInternetDisconnected();
}
}
} on SocketException catch (_) {
emitInternetDisconnected();
}
});
}
void emitInternetConnected(ConnectionType _connectionType) =>
emit(InternetConnected(connectionType: _connectionType));
void emitInternetDisconnected() => emit(InternetDisconnected());
#override
Future<void> close() async {
connectivityStreamSubscription!.cancel();
return super.close();
}
}
This is the code in the internet_state.dart file
part of 'internet_cubit.dart';
abstract class InternetState {}
class InternetLoading extends InternetState {}
class InternetConnected extends InternetState {
final ConnectionType? connectionType;
InternetConnected({required this.connectionType});
}
class InternetDisconnected extends InternetState {}
This is the code in my main.dart file
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'internet_cubit.dart';
void main() {
runApp(
BlocProvider<InternetCubit>(
create: (_) => InternetCubit(connectivity: Connectivity()),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter BLoC Demo',
home: SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("Flutter BLoC Demo"),
centerTitle: true,
backgroundColor: Colors.blue[900],
),
body: Center(
child: Builder(
builder: (context) {
return MaterialButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenOne()));
},
color: Colors.black,
textColor: Colors.white,
child: Text("Screen 1"));
},
),
),
),
),
);
}
}
class ScreenOne extends StatelessWidget {
const ScreenOne({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("Flutter BLoC Demo"),
centerTitle: true,
backgroundColor: Colors.blue[900],
),
body: Center(
child: BlocBuilder<InternetCubit, InternetState>(
builder: (_, state) {
if (state is InternetDisconnected) {
return Text("Internet disconnected");
} else if (state is InternetConnected) {
return Text("Internet connected");
}
return CircularProgressIndicator();
},
),
),
),
);
}
}
I suspected the problem to lie with my Internet connection at the network layer, so I tried a different approach. I will post my solution here so that it can be useful to someone with a similar problem.
First, I modified the internet_cubit.dart and internet_state.dart files like so:
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'internet_enum.dart';
part 'internet_state.dart';
class InternetCubit extends Cubit<InternetConnectionTypeState> {
final Connectivity? connectivity;
// ignore: cancel_subscriptions
StreamSubscription? internetConnectionTypeStreamSubscription;
InternetCubit({required this.connectivity}) : super(InternetConnectionTypeLoading()) {
monitorConnectionType();
}
void monitorConnectionType() async {
internetConnectionTypeStreamSubscription =
connectivity!.onConnectivityChanged.listen((connectivityResult) async {
if (connectivityResult == ConnectivityResult.wifi) {
emitConnectionType(ConnectionType.WiFi);
} else if (connectivityResult == ConnectivityResult.mobile) {
emitConnectionType(ConnectionType.Mobile);
}
});
}
void emitConnectionType(ConnectionType _connectionType) =>
emit(InternetConnectionType(connectionType: _connectionType));
#override
Future<void> close() async {
internetConnectionTypeStreamSubscription!.cancel();
return super.close();
}
}
part of 'internet_cubit.dart';
abstract class InternetConnectionTypeState {}
class InternetConnectionTypeLoading extends InternetConnectionTypeState {}
class InternetConnectionType extends InternetConnectionTypeState {
final ConnectionType? connectionType;
InternetConnectionType({required this.connectionType});
}
This is the internet_enum.dart file:
enum ConnectionType {
WiFi, Mobile
}
Next, I imported the internet_connection_checker package. I created a new cubit class called ConnectionCheckerCubit. Following the above code as a guide and the documentation for the internet_connection_checker package, here is the code for the connection_cubit.dart and the connection_state.dart file.
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
part 'connection_state.dart';
class ConnectionCheckerCubit extends Cubit<ConnectionCheckerState> {
final InternetConnectionChecker? internetConnectionChecker;
ConnectionCheckerCubit({required this.internetConnectionChecker}) : super(InternetConnectionLoading()) {
monitorInternetConnection();
}
// ignore: cancel_subscriptions
StreamSubscription? internetConnectionStreamSubscription;
void monitorInternetConnection() async {
internetConnectionStreamSubscription = InternetConnectionChecker().onStatusChange.listen((status) {
switch (status) {
case InternetConnectionStatus.connected:
emitInternetConnectionConnected(InternetConnectionStatus.connected);
break;
case InternetConnectionStatus.disconnected:
emitInternetConnectionDisconnected();
break;
}
});
}
void emitInternetConnectionConnected(InternetConnectionStatus _internetConnectionStatus) =>
emit(InternetConnectionConnected(internetConnectionStatus: _internetConnectionStatus));
void emitInternetConnectionDisconnected() => emit(InternetConnectionDisconnected());
#override
Future<void> close() async {
internetConnectionStreamSubscription!.cancel();
return super.close();
}
}
part of 'connection_cubit.dart';
abstract class ConnectionCheckerState {}
class InternetConnectionLoading extends ConnectionCheckerState {}
class InternetConnectionConnected extends ConnectionCheckerState {
final InternetConnectionStatus? internetConnectionStatus;
InternetConnectionConnected({required this.internetConnectionStatus});
}
class InternetConnectionDisconnected extends ConnectionCheckerState {}
In the main.dart file, I used a MultiBlocProvider in the main() function as a wrapper for runApp. In the ScreenOne widget, I used a BlocBuilder widget for the InternetCubit and used context.watch<ConnectionCheckerCubit>().state to monitor the state of the ConnectionCheckerCubit. Also, I have added a AppBlocObserver class for debugging purposes. Here is the code for the main.dart file:
import 'dart:developer';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc/bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_bloc_api/internet_enum.dart';
import 'connection_cubit.dart';
import 'internet_cubit.dart';
void main() {
Bloc.observer = AppBlocObserver();
runApp(
MultiBlocProvider(
providers: [
BlocProvider<ConnectionCheckerCubit>(
create: (_) => ConnectionCheckerCubit(internetConnectionChecker: InternetConnectionChecker()),
),
BlocProvider<InternetCubit>(
create: (_) => InternetCubit(connectivity: Connectivity()),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter BLoC Demo',
home: SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("Flutter BLoC Demo"),
centerTitle: true,
backgroundColor: Colors.blue[900],
),
body: Center(
child: Builder(
builder: (context) {
return MaterialButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenOne()));
},
color: Colors.black,
textColor: Colors.white,
child: Text("Screen 1"));
},
),
),
),
),
);
}
}
class ScreenOne extends StatelessWidget {
const ScreenOne({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("Flutter BLoC Demo"),
centerTitle: true,
backgroundColor: Colors.blue[900],
),
body: Center(
child: Builder(
builder: (context) {
final connectionState = context.watch<ConnectionCheckerCubit>().state;
final internetTypeState = context.watch<InternetCubit>().state;
if (connectionState is InternetConnectionDisconnected)
return Text("Internet Disconnected");
else if (connectionState is InternetConnectionConnected){
if (internetTypeState is InternetConnectionType && internetTypeState.connectionType == ConnectionType.WiFi)
return Text("WiFi");
else
return Text("Mobile");
}
return CircularProgressIndicator();
}
)
),
),
);
}
}
class AppBlocObserver extends BlocObserver {
#override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
log('onChange: ${bloc.runtimeType}, ${bloc.state} \nCurrent state: ${change.currentState}\nNext state: ${change.nextState}');
}
#override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
log('onError(${bloc.runtimeType}, ${bloc.state}, $error, $stackTrace)');
super.onError(bloc, error, stackTrace);
}
#override
void onEvent(Bloc bloc, Object? event) {
log('onEvent(${bloc.state}, ${bloc.runtimeType}, $event)');
super.onEvent(bloc, event);
}
#override
void onTransition(Bloc bloc, Transition transition) {
log('onTransition(${bloc.state}, ${bloc.runtimeType}, ${transition.currentState}, ${transition.nextState})');
super.onTransition(bloc, transition);
}
#override
void onCreate(BlocBase bloc) {
log('onCreate(${bloc.state}, ${bloc.runtimeType})');
super.onCreate(bloc);
}
#override
void onClose(BlocBase bloc) {
log('onTransition(${bloc.state}, ${bloc.runtimeType})');
super.onClose(bloc);
}
}
Here is a Github link for more information.
add this library connectivity: ^3.0.6
and try this code in your class:-
_startNetworkTesting(BuildContext context) async {
var result = await (Connectivity().checkConnectivity());
if (result == ConnectivityResult.none) {
setState(() {
//perform your action
});
} else if (result == ConnectivityResult.mobile) {
setState(() {
//perform your action
});
} else if (result == ConnectivityResult.wifi) {
setState(() {
//perform your action
});
}
}
I made a function to fetch data from json file and I show that data to one page when ever my fetch function run it show an erorr for the time till Json fetch that is 3 to 4 second after that data fetch and show succesfully but that error show on screen is very awkward.
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(News1());
class News1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List data = [];
#override
void initState() {
fetchData();
super.initState();
}
void fetchData() async {
final response = await http.get('jsonfilelinkhere');
if (response.statusCode == 200) {
setState(() {
data = json.decode(response.body);
});
}
}
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
return Scaffold(
body: Padding(
padding: EdgeInsets.only(left: 50 ,right: 50),
child:ListView(
children: <Widget>[
Center(
child: Text(data[3]['Head']),
),
Center(
child: Text(data[0]['Description']),
),
Image.network(data[0]['ImgUrl']),
],
),
)
);
}
}
hope you got your answer. In case you can make a check that while your array is equal to null show CircularProgressIndicator(), else show data. If you are unable to do so I can share the code for you.
your fetchData() function is asynchronous, so your app tap the back of your function saying "hi, fetchData() start to work!!" but your app goes on minding its own job.
And you gave this job for it:
child: Text(data[3]['Head']),
so your app will hit this line of code while your data variable still is an empty list.
You have to prepare it for this situation. You can prepare the default value of the data or you can check if it's empty in the Widgets that depends on it.
You encountered that error as you displayed that data before it could actually load.
Use FutureBuilder to solve your issue.
Example code:
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(News1());
class News1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List data = [];
#override
void initState() {
fetchData();
super.initState();
}
Future<Map<String, dynamic>> fetchData() async {
final response = await http.get('jsonfilelinkhere');
if (response.statusCode == 200) {
setState(() {
return json.decode(response.body);
});
}
}
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
return Scaffold(
body: Padding(
padding: EdgeInsets.only(left: 50 ,right: 50),
child:FutureBuilder<Map<String, dynamic>>(
future: fetchData, // async work
builder: (context,snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Center(child: Text('Loading....'));
default:
if (snapshot.hasError)
return Text("Error!");
else{
data = snapshot.data;
return ListView(
children: <Widget>[
Center(
child: Text(data[3]['Head']),
),
Center(
child: Text(data[0]['Description']),
),
Image.network(data[0]['ImgUrl']),
],
)}
}
},
),
)
);
}
}
I am making an app which loads the CSV and show the table on the screen but the load function is being called infinitely in the build state can anyone know how to fix it I wanted to call only once but my code called it many times.
Here is the console screenshot:
Here is the code:
import 'package:flutter/material.dart';
import 'package:csv/csv.dart';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
class TableLayout extends StatefulWidget {
#override
_TableLayoutState createState() => _TableLayoutState();
}
class _TableLayoutState extends State<TableLayout> {
List<List<dynamic>> data = [];
loadAsset() async {
final myData = await rootBundle.loadString("asset/dreamss.csv");
List<List<dynamic>> csvTable = CsvToListConverter().convert(myData);
return csvTable;
}
void load() async{
var newdata = await loadAsset();
setState(() {
data = newdata;
});
print("am i still being called called ");
}
#override
Widget build(BuildContext context) {
load();
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Apps"),),
//floatingActionButton: FloatingActionButton( onPressed: load,child: Icon(Icons.refresh),),
body: ListView(
children: <Widget>[
Container(margin: EdgeInsets.only(top: 20.0),),
Table(
border: TableBorder.all(width: 1.0,color: Colors.black),
children: data.map((item){
return TableRow(
children: item.map((row){
return Text(row.toString(),style: TextStyle(fontSize: 20.0,fontWeight: FontWeight.w900),);
}).toList(),
);
}).toList(),
),
]),
));
}
}
Here is the solution.
#override
void initState() {
super.initState();
load(); // use it here
}
#override
Widget build(BuildContext context) {
return MaterialApp(...); // no need to call initState() here
}