AudioPlayers on Flutter: I can't play mp3 one behind the other - flutter

I've been stuck for several days looking for a solution and I can't find it. I need to play mp3 files one behind the other using AudioPlayers and it is impossible for me. I'm using the only tool (as far as I know) that gives you the lib to do this kind of thing, but I can't find how to do it. Thanks for the help.
playLocal(List list) async {
list.forEach((f) async {
final file = new File('${(await getTemporaryDirectory()).path}/voice.mp3');
await file.writeAsBytes((await loadAsset(f)).buffer.asUint8List());
bool finish = false;
if (player.state == null || player.state == AudioPlayerState.COMPLETED) {
await player.play(file.path, isLocal:true);
}
if (player.state != null && player.state != AudioPlayerState.COMPLETED) {
while(!finish){
player.onPlayerCompletion.listen((event){
finish = true;
});
if (finish) {await player.play(file.path, isLocal:true);}
}
}
});
}

You can use package https://pub.dev/packages/assets_audio_player
In assetsAudioPlayer.finished.listen call _next()
code snippet
void _next() {
if (_assetsAudioPlayer.playlist != null) {
_assetsAudioPlayer.playlistNext();
} else {
_currentAssetPosition++;
_open(_currentAssetPosition);
}
}
#override
void initState() {
super.initState();
_assetsAudioPlayer.finished.listen((finished) {
print("paly next");
_next();
});
}
working demo after song1.mp3 finish auto play song2.mp3
full code
import 'package:assets_audio_player/assets_audio_player.dart';
import 'package:assets_audio_player_example/asset_audio_player_icons.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final assets = <String>[
"assets/audios/song1.mp3",
"assets/audios/song2.mp3",
"assets/audios/song3.mp3",
];
final AssetsAudioPlayer _assetsAudioPlayer = AssetsAudioPlayer();
var _currentAssetPosition = -1;
void _open(int assetIndex) {
_currentAssetPosition = assetIndex % assets.length;
_assetsAudioPlayer.open(assets[_currentAssetPosition]);
}
void _playPause() {
_assetsAudioPlayer.playOrPause();
}
void _next() {
if (_assetsAudioPlayer.playlist != null) {
_assetsAudioPlayer.playlistNext();
} else {
_currentAssetPosition++;
_open(_currentAssetPosition);
}
}
void _prev() {
if (_assetsAudioPlayer.playlist != null) {
_assetsAudioPlayer.playlistPrevious();
} else {
_currentAssetPosition--;
_open(_currentAssetPosition);
}
}
#override
void initState() {
super.initState();
_assetsAudioPlayer.finished.listen((finished) {
print("paly next");
_next();
});
}
#override
void dispose() {
_assetsAudioPlayer.stop();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Padding(
padding: const EdgeInsets.only(bottom: 48.0),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
RaisedButton(
onPressed: () {
_assetsAudioPlayer
.openPlaylist(Playlist(assetAudioPaths: this.assets));
},
child: Text("Playlist test"),
),
Expanded(
child: StreamBuilder(
stream: _assetsAudioPlayer.current,
initialData: const PlayingAudio(),
builder: (BuildContext context,
AsyncSnapshot<PlayingAudio> snapshot) {
final PlayingAudio currentAudio = snapshot.data;
return ListView.builder(
itemBuilder: (context, position) {
return ListTile(
title: Text(assets[position].split("/").last,
style: TextStyle(
color: assets[position] ==
currentAudio.assetAudioPath
? Colors.blue
: Colors.black)),
onTap: () {
_open(position);
});
},
itemCount: assets.length,
);
},
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
StreamBuilder(
stream: _assetsAudioPlayer.isLooping,
initialData: false,
builder:
(BuildContext context, AsyncSnapshot<bool> snapshot) {
return RaisedButton(
child: Text(snapshot.data ? "Looping" : "Not looping"),
onPressed: () {
_assetsAudioPlayer.toggleLoop();
},
);
},
),
SizedBox(width: 20),
RaisedButton(
child: Text("Seek to 2:00"),
onPressed: () {
_assetsAudioPlayer.seek(Duration(minutes: 2));
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder(
stream: _assetsAudioPlayer.currentPosition,
initialData: const Duration(),
builder: (BuildContext context,
AsyncSnapshot<Duration> snapshot) {
Duration duration = snapshot.data;
return Text(durationToString(duration));
},
),
Text(" - "),
StreamBuilder(
stream: _assetsAudioPlayer.current,
builder: (BuildContext context,
AsyncSnapshot<PlayingAudio> snapshot) {
Duration duration = Duration();
if (snapshot.hasData) {
duration = snapshot.data.duration;
}
return Text(durationToString(duration));
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
IconButton(
onPressed: _prev,
icon: Icon(AssetAudioPlayerIcons.to_start),
),
StreamBuilder(
stream: _assetsAudioPlayer.isPlaying,
initialData: false,
builder:
(BuildContext context, AsyncSnapshot<bool> snapshot) {
return IconButton(
onPressed: _playPause,
icon: Icon(snapshot.data
? AssetAudioPlayerIcons.pause
: AssetAudioPlayerIcons.play),
);
},
),
IconButton(
icon: Icon(AssetAudioPlayerIcons.to_end),
onPressed: _next,
),
],
),
],
),
),
),
);
}
}
String durationToString(Duration duration) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
String twoDigitMinutes =
twoDigits(duration.inMinutes.remainder(Duration.minutesPerHour));
String twoDigitSeconds =
twoDigits(duration.inSeconds.remainder(Duration.secondsPerMinute));
return "$twoDigitMinutes:$twoDigitSeconds";
}

Related

How to make BLoC instance persistent?

I'm developing an app using movies database API. I want to read a list of the movies and then choose one and display the details to user.
MovieDetailsBloc code:
import 'package:bloc/bloc.dart';
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_recruitment_task/movie_details/models/movie_details.dart';
import 'package:flutter_recruitment_task/services/api_service.dart';
import 'package:stream_transform/stream_transform.dart';
part 'movie_details_event.dart';
part 'movie_details_state.dart';
const throttleDuration = Duration(milliseconds: 100);
EventTransformer<E> throttleDroppable<E>(Duration duration) {
return (events, mapper) {
return droppable<E>().call(events.throttle(duration), mapper);
};
}
class MovieDetailsBloc extends Bloc<MovieDetailsEvent, MovieDetailsState> {
MovieDetailsBloc({required this.apiService}) : super(MovieDetailsState()) {
on<MovieSelected>(
_onMovieSelected,
transformer: throttleDroppable(throttleDuration),
);
}
final ApiService apiService;
Future<void> _onMovieSelected(MovieSelected event, Emitter<MovieDetailsState> emit) async {
try{
final movie = await _fetchMovieDetails(event.query);
return emit(state.copyWith(
status: MovieDetailsStatus.success,
movie: movie,
));
} catch (_) {
emit(state.copyWith(status: MovieDetailsStatus.failure));
}
}
Future<MovieDetails> _fetchMovieDetails(String id) async {
final movie = apiService.fetchMovieDetails(id);
return movie;
}
String shouldIWatchIt() {
final movie = state.movie;
if(movie.revenue - movie.budget > 1000000 && DateTime.now().weekday == DateTime.sunday){
return 'Yes';
} else {
return 'No';
}
}
}
MovieListPage code:
import 'package:flutter/material.dart';
import 'package:flutter_recruitment_task/movie_details/bloc/movie_details_bloc.dart';
import 'package:flutter_recruitment_task/movies/bloc/movies_bloc.dart';
import 'package:flutter_recruitment_task/movies/models/movie.dart';
import 'package:flutter_recruitment_task/pages/movie_details/movie_details_page.dart';
import 'package:flutter_recruitment_task/pages/movie_list/movie_card.dart';
import 'package:flutter_recruitment_task/pages/movie_list/search_box.dart';
import 'package:flutter_recruitment_task/services/api_service.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MovieListPage extends StatefulWidget {
#override
_MovieListPage createState() => _MovieListPage();
}
class _MovieListPage extends State<MovieListPage> {
final ApiService apiService = ApiService();
late final MoviesBloc moviesBloc;
late final MovieDetailsBloc movieDetailsBloc;
void _onSearchBoxSubmitted(String text) {
moviesBloc.add(MoviesFetched(query: text));
}
#override
void initState() {
moviesBloc = MoviesBloc(apiService: apiService);
movieDetailsBloc = MovieDetailsBloc(apiService: apiService);
super.initState();
}
#override
void dispose() {
movieDetailsBloc.close();
moviesBloc.close();
super.dispose();
}
#override
Widget build(BuildContext context) => BlocProvider(
create: (_) => movieDetailsBloc,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.movie_creation_outlined),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => MovieDetailsPage(
movieDetailsBloc: movieDetailsBloc,
)
)
);
},
),
],
title: Text('Movie Browser'),
),
body: BlocProvider(
create: (_) => moviesBloc,
child: Column(
children: <Widget>[
SearchBox(onSubmitted: _onSearchBoxSubmitted),
Expanded(child: _buildContent()),
],
),
),
),
);
Widget _buildContent() => BlocBuilder<MoviesBloc, MoviesState>(
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
switch (state.status) {
case MoviesStatus.failure:
return const Center(child: Text('failed to fetch movies'));
case MoviesStatus.success:
if (state.movies.isEmpty) {
return const Center(child: Text('no movies'));
}
return _buildMoviesList(state.movies);
case MoviesStatus.initial:
return const Center(child: CircularProgressIndicator());
}
});
Widget _buildMoviesList(List<Movie> movies) => ListView.separated(
separatorBuilder: (context, index) => Container(
height: 1.0,
color: Colors.grey.shade300,
),
itemBuilder: (context, index) => BlocBuilder<MovieDetailsBloc, MovieDetailsState>(
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
return MovieCard(
title: movies[index].title,
rating: '${(movies[index].voteAverage * 10).toInt()}%',
color: state.movie.title == movies[index].title ?
Colors.amberAccent : Colors.white,
onTap: () {
movieDetailsBloc.add(MovieSelected(query: movies[index].id.toString()));
},
);
}
),
itemCount: movies.length,
);
}
MovieDetailsPage code:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_recruitment_task/movie_details/bloc/movie_details_bloc.dart';
import 'package:flutter_recruitment_task/movie_details/models/movie_detail_placeholder.dart';
class MovieDetailsPage extends StatefulWidget {
final MovieDetailsBloc? movieDetailsBloc;
const MovieDetailsPage({super.key, this.movieDetailsBloc});
#override
_MovieDetailsPageState createState() => _MovieDetailsPageState();
}
class _MovieDetailsPageState extends State<MovieDetailsPage> {
var _details = [];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => BlocProvider(
create: (_) => widget.movieDetailsBloc!,
child: BlocBuilder<MovieDetailsBloc, MovieDetailsState>(
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
_details = [
MovieDetailPlaceholder(title: 'Budget', content: '\$ ${state.movie.budget}'),
MovieDetailPlaceholder(title: 'Revenue', content: '\$ ${state.movie.revenue}'),
MovieDetailPlaceholder(title: 'Should I watch it today?', content: widget.movieDetailsBloc!.shouldIWatchIt()),
];
return Scaffold(
appBar: AppBar(
title: Text(state.movie.title),
),
body: ListView.separated(
separatorBuilder: (context, index) => Container(
height: 1.0,
color: Colors.grey.shade300,
),
itemBuilder: (context, index) => Container(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
_details[index].title,
style: Theme.of(context).textTheme.headline5,
),
SizedBox(height: 8.0),
Text(
_details[index].content,
style: Theme.of(context).textTheme.subtitle1,
),
],
),
),
itemCount: _details.length,
),
);
}
),
);
}
I'm passing an instance of BLoC from MovieListPage to MovieDetailsPage because it holds the details of the movie to display. It works fine for one time, however when I go back to the MovieListPage I'm not able to choose a new movie to display the details. How I can make an instance of BLoC persist through navigation?
Create your bloc's intance after your bloc ends like
class MovieDetailsBloc extends Bloc<MovieDetailsEvent, MovieDetailsState> {
MovieDetailsBloc({required this.apiService}) : super(MovieDetailsState()) {
on<MovieSelected>(
_onMovieSelected,
transformer: throttleDroppable(throttleDuration),
);
}
final ApiService apiService;
Future<void> _onMovieSelected(MovieSelected event, Emitter<MovieDetailsState> emit) async {
try{
final movie = await _fetchMovieDetails(event.query);
return emit(state.copyWith(
status: MovieDetailsStatus.success,
movie: movie,
));
} catch (_) {
emit(state.copyWith(status: MovieDetailsStatus.failure));
}
}
Future<MovieDetails> _fetchMovieDetails(String id) async {
final movie = apiService.fetchMovieDetails(id);
return movie;
}
String shouldIWatchIt() {
final movie = state.movie;
if(movie.revenue - movie.budget > 1000000 && DateTime.now().weekday == DateTime.sunday){
return 'Yes';
} else {
return 'No';
}
}
}
MovieDetailsBloc movieDetailsBloc = MovieDetailsBloc();
and you can access it anywhere in your code with movieDetailsBloc.add or whatever you want.

LateInitializationError error in flutter_map

I set up flutter_map succesfully, but when I try to filter my map by "City" for example I am getting this error:
The following LateError was thrown building FutureBuilder<List<dynamic>>(dependencies: [MediaQuery],
state: _FutureBuilderState<List<dynamic>>#cb20d):
LateInitializationError: Field '_state' has already been initialized.
The relevant error-causing widget was:
FutureBuilder<List<dynamic>>
My flutter_map implementation is as follow:
late MapController mapController;
Future<List<dynamic>>? futureLocs;
Future<List<dynamic>>? futureLocsFilteredByCity;
bool? isFilterByCity;
PageController pageController = PageController();
double currentZoom = 10.0;
PanelController panelController = PanelController();
#override
void initState() {
super.initState();
mapController = MapController();
pageController = PageController(viewportFraction: 0.7, initialPage: 0);
futureLocs = getAllDogsLocation();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: GenericAppBar(context,
backbutton: true,
title: 'Dogs map',
filterbutton: true, onfilterpress: () {
showDialog(
context: context,
builder: (context) {
return CitiesToFilter(
futureLocs: futureLocs,
onCityPress: (city) {
setState(() {
isFilterByCity = true;
futureLocs = getDogLocationByCity(city);
futureLocs!.then((value) {
if (value.isNotEmpty) {
var latlong = LatLng(
value[0]['latitude'], value[0]['longitude']);
widget.lat = latlong.latitude;
widget.long = latlong.longitude;
}
});
});
});
});
}),
body: FlutterMapCusto(
futureLocs: futureLocs,
mapController: mapController,
pageController: pageController,
lat: widget.lat,
long: widget.long,
panelcontroller: panelController,
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
heroTag: Text('CurrentLoc'),
onPressed: () {
setState(() {
mapController.move(
LatLng(widget.lat, widget.long), currentZoom);
});
},
tooltip: 'Current location',
child: const Icon(Icons.location_history),
),
],
));
}
}
where FlutterMapCusto widget is defined as a normal widget with FlutterMap class. I am not including it to avoid boilerplate code here since it is a basic implementation found in the package web. I think the error is coming from mapController..
On the other hand I am fetching my new data filtered by city with the function "getDogLocationByCity(city)" updating my future.
Then we have CitiesToFilter widget:
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Filter'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Filter by City'),
FloatingActionButton(onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Cities:'),
content: SizedBox(
width: MediaQuery.of(context).size.width,
child: FutureBuilder(
future: widget.futureLocs,
builder: (BuildContext context,
AsyncSnapshot<List<dynamic>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Text('Loading...');
case ConnectionState.active:
{
return const Center(
child: Text('Loading...'),
);
}
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'Error: ${snapshot.error}');
}
if (snapshot.hasData) {
return ListView.builder(
itemCount:
snapshot.data!.length,
itemBuilder: (context, index) {
return TextButton(
onPressed: () {
setState(() {
widget.onCityPress( snapshot.data![index]['CityName'] );
});
Navigator.pop(context);
},
child: Text(
snapshot.data![index]
['CityName']));
});
} else {
return const Text(
'No data available');
}
}
},
),
),
);
});
})
],
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Close'))
],
);
}
Future method to fetch the data shown in map. This is just a wrapper developed from Back4App to interact with its MongoDb database:
Future<List<dynamic>> getAllDogsLocation() async {
await Future.delayed(const Duration(seconds: 2), () {});
QueryBuilder<ParseObject> queryTodo =
QueryBuilder<ParseObject>(ParseObject('Todo'));
// queryTodo.includeObject(['latitude']);
final ParseResponse apiResponse = await queryTodo.query();
if (apiResponse.success && apiResponse.results != null) {
return apiResponse.results as List<ParseObject>;
} else {
throw Exception('Failed to load data');
}
}

flutter carousel slider doesn't refresh items

i am new at flutter, so i tried to implement carousel slider with images, i receive an List with my model from server and i created widget but it shows only 1 item from 18... I mean it always show 1 item, but all list is passed
But if i make hot reload then i receive all items, i hope i could explain... my dart code
import 'dart:convert';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:vltest/Models/_easyloaderslist.dart';
import 'Models/_workers.dart';
import 'Widgets/navigation_drawer_widget.dart';
import 'database.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
late List<EasyLoadersList> imgList = List.empty();
class Landing extends StatefulWidget {
#override
_LandingState createState() => _LandingState();
}
Future<List<EasyLoadersList>> _getLoaders(Workers workers) async {
final response = await http.get(
Uri.parse(
'http://url'),
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer ${workers.token}"
});
if (response.statusCode == 200) {
Iterable l = json.decode(response.body);
List<EasyLoadersList> loaders = List<EasyLoadersList>.from(
l.map((model) => EasyLoadersList.fromJson(model)));
return loaders;
} else {
throw Exception('Failed to load album');
}
}
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
showWorkerDialog(BuildContext context, Workers album) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {
Navigator.pop(context);
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(album.name),
content: Text("Hi, ${album.name}"),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
class _LandingState extends State<Landing> {
String _username = "";
late List<EasyLoadersList> loaders = List.empty();
int _current = 0;
#override
void initState() {
super.initState();
_loadUserInfo();
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavigationDrawerWidget(),
appBar: AppBar(
title: Text('User info'),
),
body: RefreshIndicator(
onRefresh: () async {
_loadUserInfo();
},
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CarouselSlider.builder(
itemCount: imgList.length,
itemBuilder: (context, index, realIndex) {
if (imgList.length != 0) {
return buildImage(imgList[index]);
} else {
return loadingData(context);
}
},
options: CarouselOptions(height: 500),
),
]),
),
),
);
}
Widget buildImage(EasyLoadersList loadersList) => Column(
mainAxisSize: MainAxisSize.max,
children: [
AspectRatio(
aspectRatio: 1,
child: Image.network(
loadersList.url,
fit: BoxFit.fill,
),
),
const SizedBox(
height: 30,
),
Text("Address :" + loadersList.shopAddress),
Text("Serial:" + loadersList.serialNumber),
Text("Hours :" + loadersList.currentMotoHours),
Text("Current:" + loadersList.currentMotoHoursUntilTO),
Text("Next:" + loadersList.remainsMotoHoursUntilTO),
Text("Last Use:" + loadersList.lastMotoHoursEditDate),
],
);
Widget loadingData(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'Loading...',
style: Theme.of(context).textTheme.headline6,
),
CircularProgressIndicator(
semanticsLabel: 'Loading...',
),
],
),
),
);
}
Future<void> _loadUserInfo() async {
Workers workers = await DBProvider.db.getWorkerInfo();
final prefs = await SharedPreferences.getInstance();
showWorkerDialog(context, workers);
imgList = await _getLoaders(workers);
}
}
Cant see any setState to update the UI. try adding setState on end of refresh like.
onRefresh: () async {
await _loadUserInfo();
setState((){});
},
And on initState
_loadUserInfo().then((value) {setState((){})}):
Or
Future<void> _loadUserInfo() async {
.....
imgList = await _getLoaders(workers);
setState((){});
}

The search bar does not return any results

I am trying to add a search function in my flutter app, the search bar is showing and there's not errors but its not working and it doesn't return any results.
the data list is from an API that I already called using the rest API
// ignore_for_file: use_key_in_widget_constructors, avoid_print, avoid_unnecessary_containers, curly_braces_in_flow_control_structures, prefer_const_constructors, non_constant_identifier_names, unnecessary_new, avoid_function_literals_in_foreach_calls, unused_import, avoid_types_as_parameter_names, unused_label
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:myapp2/Service_Request/SR.dart';
import 'package:myapp2/main.dart';
import 'package:myapp2/Service_Request/second.dart';
import '../Classes/demandes.dart';
import 'SR_details.dart';
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DataFromAPI(),
);
}
}
class DataFromAPI extends StatefulWidget {
#override
_DataFromAPIState createState() => _DataFromAPIState();
}
List<Attributes> _MyAllData = [];
var _srAttributes = [];
class _DataFromAPIState extends State<DataFromAPI> {
#override
void initState() {
loadData().then((value) {
setState(() {
_srAttributes.addAll(value);
});
});
super.initState();
}
Future<List<Sr>> loadData() async {
try {
var response = await http.get(Uri.parse(
'http://192.168.1.30:9080/maxrest/rest/mbo/sr/?_lid=azizl&_lpwd=max12345m&_format=json'));
if (response.statusCode == 200) {
final jsonBody = json.decode(response.body);
Demandes data = Demandes.fromJson(jsonBody);
final srAttributes = data.srMboSet.sr;
return srAttributes;
}
} catch (e) {
throw Exception(e.toString());
}
throw Exception("");
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text('Liste des Demandes'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => SR()))),
),
body: FutureBuilder<List<Sr>?>(
future: loadData(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
return new ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: ((_, index) {
return index == 0
? _searchbar()
: new ListTile(
title: new Card(
margin: new EdgeInsets.symmetric(
vertical: 2.0, horizontal: 8.0),
elevation: 10,
child: new ListTile(
title: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(padding: new EdgeInsets.all(2.0)),
new Text(
'Ticket ID : ${snapshot.data![index].attributes.ticketid.content}'),
new Text(
'status : ${snapshot.data![index].attributes.status.content}'),
new Text(
'description : ${snapshot.data![index].attributes.description?.content}'),
new Text(
'Reported by : ${snapshot.data![index].attributes.reportedby.content}'),
new Text(
'Reoprt date : ${snapshot.data![index].attributes.statusdate.content}'),
],
),
trailing: Icon(Icons.arrow_forward_ios_rounded),
),
),
onTap: () {
Navigator.of(context)
.push(
new MaterialPageRoute(
builder: (BuildContext context) =>
new SrDetailsScreen(
sr: snapshot.data![index]),
),
)
.then((data) {});
});
}),
);
}
},
),
),
);
}
_searchbar() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Search ..."),
onChanged: (text) {
text = text.toLowerCase();
setState(() {
_srAttributes = _MyAllData.where((srAttributes) {
var idticket = srAttributes.description!.content.toLowerCase();
return idticket.contains(text);
}).toList();
});
},
),
);
}
}
FutureBuilder loads values of current future. You are assigning a function result to FutureBuilder so its value always changes dynamically.
Create variable to keep Future's value.
Future<List<Sr>>? dataToLoad;
Whenever you want to load data from server ( for example, on text changed ):
setState((){
dataToLoad = loadData();
});
And use it in FutureBuilder:
FutureBuilder<List<Sr>?>(
future: dataToLoad,

unnecessary container but I need this container? flutter/Dart

I am working on a app were I get data from the ESP32 and display it on a simple page. Here is my code for my sensorpage:
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
class sensorpage extends StatefulWidget {
const sensorpage({Key? key, required this.device}) : super(key: key);
final BluetoothDevice device;
#override
_sensorpageState createState() => _sensorpageState();
}
class _sensorpageState extends State<sensorpage> {
final String SERVICE_UUID = "edb91e04-3e19-11ec-9bbc-0242ac130002";
final String CHARACTERISTIC_UUID = "edb920c0-3e19-11ec-9bbc-0242ac130002";
late bool isReady;
//String val1 = "";
//int pot1 = 0;
FlutterBlue flutterBlue = FlutterBlue.instance;
//late StreamSubscription<ScanResult> scanSubScription;
//late BluetoothDevice targetDevice;
late Stream<List<int>> stream;
#override
void initState() {
super.initState();
isReady = false;
connectToDevice();
}
connectToDevice() async {
if (widget.device == null) {
_Pop();
return;
}
Timer(const Duration(seconds: 15), () {
if (!isReady) {
disconnectFromDevice();
_Pop();
}
});
await widget.device.connect();
discoverServices();
}
disconnectFromDevice() {
if (widget.device == null) {
_Pop();
return;
}
widget.device.disconnect();
}
discoverServices() async {
if (widget.device == null) {
_Pop();
return;
}
List<BluetoothService> services = await widget.device.discoverServices();
services.forEach((service) {
if (service.uuid.toString() == SERVICE_UUID) {
service.characteristics.forEach((characteristic) {
if (characteristic.uuid.toString() == CHARACTERISTIC_UUID) {
characteristic.setNotifyValue(!characteristic.isNotifying);
stream = characteristic.value;
setState(() {
isReady = true;
});
}
});
}
});
if (!isReady) {
_Pop();
}
}
Future<bool> _onWillPop() async {
bool shouldPop = false;
await showDialog(
context: context,
builder: (context) =>
AlertDialog(
title: const Text('Are you sure?'),
content: const Text('Do you want to disconnect device and go back?'),
actions: <Widget>[
ElevatedButton(
onPressed: () {
// shouldPop is already false
},
child: const Text('No')),
ElevatedButton(
onPressed: () async {
await disconnectFromDevice();
Navigator.of(context).pop();
shouldPop = true;
},
child: const Text('Yes')),
],
));
return shouldPop;
}
_Pop() {
Navigator.of(context).pop(true);
}
String _dataParser( List<int> dataFromDevice) {
return utf8.decode(dataFromDevice);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: const Text('Test'),
),
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError){
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.active) {
var currentValue = _dataParser (snapshot.data!);
//val1 = currentValue.split(',')[0];
//pot1 = int.parse(val1);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Current value',
style: TextStyle(fontSize: 14)),
Text('${currentValue} jawool',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24))
])
);
} else {
return const Text('Check the stream');
}
},
)),
)
));
}
}´
My Problem is that my second container where I display my data is shown as unnecessary but I don´t know why.
I assume you mean this piece of code?
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
If isReady is true you return Container(child: Container(child: SteamBuilder));
You should change it to this and it should be fine:
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: StreamBuilder<List<int>>(
The first Container is just wrapping the content based on the boolean and you don't need it. According to the flutter team:
Wrapping a widget in Container with no other parameters set has no effect and makes code needlessly more complex
So instead you can directly do:
body: !isReady ? buildSomething() : Container(....more code);