Flutter Error when changing DropDownButton Selection - flutter

Error:
Failed assertion: line 609 pos 15: 'items == null ||
I/flutter (24295): items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) => item.value ==
I/flutter (24295): value).length == 1': is not true.
I did some research and did not figure out what caused the problem. Here is my code:
class StatusList extends StatefulWidget {
#override
_StatusListState createState() => _StatusListState();
}
class _DispositionListState extends State<DispositionList> {
var _currentSelectedValue = '';
Future<RecordList> recordList;
#override
void initState() {
recordList = getRecord();
super.initState();
}
int i = 1;
List<String> statusList = List<String>();
#override
Widget build(BuildContext context) {
return FutureBuilder<RecordList>(
future: recordList,
builder: (context, snapshot) {
if (snapshot.hasData) {
String current = snapshot.data.record[0].status.trim();
statusList.add(snapshot.data.record[0].status.trim());
while (i < snapshot.data.record.length) {
if (snapshot.data.record[i].status.trim() != current) {
statusList.add(snapshot.data.record[i].status.trim());
current = snapshot.data.record[i].status.trim();
}
i++;
}
_currentSelectedValue = statusList[0]; //not set this will straight getting error
return DropdownButton(
items: statusList.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: SizedBox(
width: 200.0,
child: Text(
dropDownStringItem,
overflow: TextOverflow.ellipsis,
),
));
}).toList(),
onChanged: (String valueSelected) {
onDropDownSelected(valueSelected);
},
value: _currentSelectedValue,
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
});
}
void onDropDownSelected(String valueSelected) {
setState(() {
this._currentSelectedValue = valueSelected;
});
}
}
I tried compare the recordList and the valueSelected in onDropDownSelected return true. Problem caused when the setState is called even without any code inside. Anyone idea of what caused the problem based on these code?
Added code: Here is my getRecord()
Future<RecordList> getRecord() async {
String url = 'some url';
final response = await http.get(url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
return RecordList.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load post');
}
}
class Record {
final String status;
final String disposition;
final int total;
Record({this.status, this.disposition, this.total});
factory Record.fromJson(Map<String, dynamic> json) {
return Record(
status: json['status'],
disposition: json['disposition'],
total: json['total']);
}
}
class RecordList {
final List<Record> record;
RecordList({this.record});
factory RecordList.fromJson(List<dynamic> parsedJson) {
List<Record> record = new List<Record>();
record = parsedJson.map((i) => Record.fromJson(i)).toList();
return new RecordList(
record: record,
);
}
}

It can be that the value property of DropdownButton has the value which is not one of item's value. value property should be either null or one of the item's value.
Also, maybe you don't need a FutureBuilder here. You can do something like that:
class _DispositionListState extends State<DispositionList> {
bool _isLoading = true;
String _currentSelectedValue;
List<String> statusList = List<String>();
#override
void initState() {
super.initState();
_loadStatusList();
}
_loadStatusList() async {
final recordList = await getRecord();
final list = recordList.record.map((r) {
return r.status.trim();
}).toSet().toList();
setState(() {
statusList = list;
_currentSelectedValue = list.first;
_isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return isLoading ? CircularProgressIndicator() : _buildDropdown();
}
Widget _buildDropdown() {
return DropdownButton(
items: statusList.map((dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: SizedBox(
width: 200.0,
child: Text(
dropDownStringItem,
overflow: TextOverflow.ellipsis,
),
),
);
}).toList(),
onChanged: (valueSelected) {
onDropDownSelected(valueSelected);
},
value: _currentSelectedValue,
);
}
void onDropDownSelected(String valueSelected) {
setState(() {
this._currentSelectedValue = valueSelected;
});
}
}
Update: Added .toSet() to filter out duplicates from statusList
I think the problem is that the status list has duplicated items. I added .toSet() before .toList() to filter out duplicates. Set is a collection of objects in which each object can occur only once.

Related

Infinite scroll loading Pagination problem in ListView Flutter

Problem with displaying images in ListView, have error app crash when load all images at once and pagination code i have now is not work for some reason
Basicly want to fetch images from this firebase colection and display them in 'ListView' with pagination to my app not crash.
Hopfuly somebody can help me fix this issue, thank you!
initSliderImages() async {
var result = await FirebaseFirestore.instance.collection('galerytab1');
result.snapshots().listen((data) {
List imgs = [];
data.docChanges.forEach((change) {
var imageData = change.doc.data();
String image = imageData?['url'];
imgs.add(CachedNetworkImage(imageUrl: image));
});
setState(() {
images = imgs;
});
});
}
class _CategoryTab1State extends State<CategoryTab1> {
List images = [];
late ScrollController controller;
final scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
// addUrls();
controller = ScrollController()..addListener(_scrollListener);
initSliderImages();
if (this.mounted) {
context.read<CategoryTab1Bloc>().data.isNotEmpty
? print('data already loaded')
: context.read<CategoryTab1Bloc>().getData(mounted, widget.category);
}
}
#override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
void _scrollListener() {
print(controller.position.extentAfter);
if (controller.position.extentAfter < 2) {
setState(() {
print('add 2 more');
print('add 2 more');
print('add 2 more');
print('add 2 more');
// images.addAll(['item1','item2','item3']
// List.generate(2, (index) => 'Inserted $index'
// )
// );
});
}
}
// //
// void addUrls() {
// final List<String> imgs = List.generate(
// 16,
// (_) {
// int random = Random().nextInt(16) + 16; // 250-500
// return
// // initSliderImages();
// // 'https://picsum.photos/$random/$random';
// 'https://firebasestorage.googleapis.com/v0/b/klosterkatz-c914e.appspot.com/o/galerytab1%2F1.png?alt=media&token=5b0e9c74-ec5a-42ca-aa59-309f41938a28';
//
//
//
//
// },
// );
// setState(() {
// images.addAll(imgs);
// });
// }
//
// Fetch images from databse for list
initSliderImages() async {
final int _limit = 3;
var result = await FirebaseFirestore.instance.collection('galerytab1');
result.snapshots().listen((data) {
List imgs = [];
data.docChanges.forEach((change) {
var imageData = change.doc.data();
String image = imageData?['url'];
imgs.add(image);
});
setState(() {
images = imgs;
});
});
}
#override
Widget build(BuildContext context) {
print('imagesimageimagesimagesimageismageimage');
print('$images');
print(images.length);
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification.metrics.pixels ==
notification.metrics.maxScrollExtent) {
initSliderImages();
_scrollListener();
// addUrls();
}
return true;
},
child:
ListView.builder(
controller: controller,
key: widget.key,
itemCount: images.length,
itemExtent: 250,
itemBuilder: (context, index) {
return CachedNetworkImage(
imageUrl: images[index],
fit: BoxFit.cover,
key: ValueKey(images[index]),
);
}
),
);
}
}
In listview.Builder add shrinkWrap : primary false if not true
App is crashing due to memory issue. Following code is for proper pagination using firestore. Hope it will help you.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
class CategoryTab1 extends StatefulWidget {
const CategoryTab1({Key? key}) : super(key: key);
#override
State<CategoryTab1> createState() => _CategoryTab1State();
}
class _CategoryTab1State extends State<CategoryTab1> {
final _controller = ScrollController();
var _images = <String>[];
/// Flag for first time loading
var _isLoading = true;
/// Flag for paginated loading
var _isSubLoading = false;
/// last snapshot reference for pagination
QueryDocumentSnapshot<Map<String, dynamic>>? _lastSnapshot;
/// length of last images fetched
var _length = 10;
/// can load more if length is equal or more than 10
/// if less than 10 it means all images have been fetched
bool get _canLoadMore => _length >= 10;
#override
void initState() {
super.initState();
_loadData();
_controller.addListener(_listener);
}
#override
void dispose() {
_controller.removeListener(_listener);
_controller.dispose();
super.dispose();
}
void _listener() {
if (!_canLoadMore) {
return;
}
if (_isSubLoading || _isLoading) {
return;
}
if (_controller.position.extentAfter <= 0) {
_loadData();
}
}
final _collection = FirebaseFirestore.instance.collection('galerytab1');
void _loadData() async {
try {
if (_lastSnapshot != null) {
_isSubLoading = true;
setState(() {});
}
late QuerySnapshot<Map<String, dynamic>> _result;
/// Fetching images
if (_lastSnapshot == null) {
/// First time loading
_result = await _collection.limit(10).get();
} else {
/// Paginated loading
_result = await _collection
.startAfterDocument(_lastSnapshot!)
.limit(10)
.get();
}
final docs = _result.docs;
_length = docs.length;
for (final doc in docs) {
String im = doc.data()['url'] ?? '';
if (im.isNotEmpty) _images.add(im);
}
if (docs.isNotEmpty) _lastSnapshot = docs.last;
} catch (_) {}
_isLoading = false;
_isSubLoading = false;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView.builder(
controller: _controller,
itemCount: _images.length,
addAutomaticKeepAlives: true,
itemBuilder: (context, index) {
return CachedNetworkImage(
imageUrl: _images[index],
fit: BoxFit.cover,
key: ValueKey(_images[index]),
);
},
),
),
if (_isSubLoading) CircularProgressIndicator(),
],
),
);
}
}

The element type 'Future<List<Organization>>?' can't be assigned to the list type 'Widget'

class Organization_Api{
static Future<List<dynamic>> getData(
{required String target, String? limit}) async {
try {
var uri = Uri.https(
BASE_URL,
"api/$target",
target == "organizations"
? {
"offset": "0",
"limit": limit,
}
: {});
var response = await http.get(uri);
var data = jsonDecode(response.body);
List tempList = [];
if (response.statusCode != 200) {
throw data["message"];
}
for (var v in data) {
tempList.add(v);
}
return tempList;
} catch (error) {
log("An error occured $error");
throw error.toString();
}
}
static Future<List<Organization>> getAllOrganizations(
{required String limit}) async {
List temp = await getData(
target: "organizations",
limit: limit,
);
return Organization.organizationsToList(temp);
}
static Future<Organization> getOrganizationById({required String id}) async {
try {
var uri = Uri.https(
BASE_URL,
"api/organizations/$id",
);
var response = await http.get(uri);
var data = jsonDecode(response.body);
if (response.statusCode != 200) {
throw data["message"];
}
return Organization.fromJson(data);
} catch (error) {
log("an error occured while getting organization info $error");
throw error.toString();
}
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static String routeName = "/home";
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Future<List<Organization>>? result ;
void initState(){
result = Organization_Api.getAllOrganizations(limit: '4');
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Organizations", style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.white,
centerTitle: true,
),
body: Padding(
padding: EdgeInsets.all(10.0),
child: Column(
children:
<Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children:<Widget>[
ListView(
shrinkWrap: true,
children:<Widget> [result],
)
],
),
)
],
),
),
);
}
}
class Organization{
final int OrganizationId;
final String OrganizationName;
Organization({required this.OrganizationId,required this.OrganizationName});
factory Organization.fromJson(Map<String,dynamic> json){
return Organization(OrganizationId: json['OrganizationId'], OrganizationName: json['OrganizationName']);
}
Map toJson(){
return{
"OrganizationId": this.OrganizationId,
"OrganizationName": this.OrganizationName,
};
}
static List<Organization> organizationsToList(List organizationToList) {
return organizationToList.map((data) {
return Organization.fromJson(data);
}).toList();
}
}
Error = The element type >'Future<List>?' can't be assigned to the list type 'Widget'.
I just want to check the data coming from the service, but I couldn't find how to do it.
What did I do wrong or what did I miss to list the incoming data?
I shared the screen page and the codes on how I got the information from the service.
Your Organization_Api.getAllOrganizations provide a future. You can use FutureBuilder.
class _HomeScreenState extends State<HomeScreen> {
Future<List<Organization>>? myFuture;
#override
void initState() {
myFuture = Organization_Api.getAllOrganizations(limit: '4');
super.initState();
}
And on future builder
FutureBuilder<List<Organization>?>(
future: myFuture,
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return ListView(
shrinkWrap: true,
//children: snapshot.data!, // when `Organization` is a widget
children:// when `Organization` is a data model class
snapshot.data!.map((e) => Text(e.toString())).toList(),
);
}
return CircularProgressIndicator();
},
)
Also check Randal L. Schwartz video on using Future

Read data from Flutter via Bluetooth

I am trying to get the data from my bluetooth device. My problem is with the Flutter code to get such data.
services/sensor.dart
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:minertti/main.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> {
String service_uuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
String charaCteristic_uuid = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
late bool isReady;
late Stream<List<int>> stream;
late List _temphumidata;
double _charge = 0;
double _data_1 = 0;
double _data_2 = 0;
#override
void initState() {
super.initState();
super.initState();
isReady = false;
connectToDevice();
}
void dispose() {
widget.device.disconnect();
super.dispose();
}
connectToDevice() async {
if (widget.device == null) {
_pop();
return;
}
new 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().isNotEmpty) {
service.characteristics.forEach((characteristic) {
if (characteristic.uuid.toString().isNotEmpty) {
characteristic.setNotifyValue(!characteristic.isNotifying);
stream = characteristic.value;
setState(() {
isReady = true;
});
}
});
}
});
if (!isReady) {
_pop();
}
}
_pop() {
Navigator.of(context).pop(true);
}
String _dataParser(List<int> dataFromDevice) {
return utf8.decode(dataFromDevice);
}
#override
Widget build(BuildContext context) {
return Scaffold(
// appBar: AppBar(
// title: Text('dht11 Sensor'),
// ),
body: Container(
child: !isReady
? Center(
child: Text(
"Waiting...",
style: TextStyle(
fontSize: 24, color: Color.fromARGB(255, 0, 0, 0)),
),
)
: 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 data = snapshot.data as List<int>;
var currentValue = _dataParser(data);
print("REALDATA: $data");
_temphumidata = currentValue.split(",");
//_charge = double.parse('${_temphumidata[0]}');
//_data_1 = double.parse('${_temphumidata[1]}');
//_data_2 = _temphumidata[2];
return DeviceScreen1(
device: widget.device,
//charge: _charge,
//data_2: _data_2,
//data_1: _data_1,
charge: 90,
data_1: "Data 1",
data_2: "Data 2");
} else {
return Text('Check the stream');
}
},
),
)),
);
}
}
var data = snapshot.data as List;
var currentValue = _dataParser(data);
They do not show values. But, from my Arduino I know that it does send/notify data. That is, my problem is with reading and obtaining said data.

Flutter: ListView not displaying anything + lazy loading

I am new in flutter and trying to create a listview with load more functionality.
Here is my class. It is not displaying anything, blank screen. List has data I am getting result in console.
class ReportPurchaseNew extends StatefulWidget {
final AdminUserDetails userDetails;
final String title;
const ReportPurchaseNew({Key key, this.title, this.userDetails})
: super(key: key);
#override
State<StatefulWidget> createState() => new ReportPurchaseState();
}
class ReportPurchaseState extends State<ReportPurchaseNew> {
String fromDate = "", toDate = "", usageType = "";
int limit = 7, offset = 0;
static int page = 0;
List<Result> _List = new List();
List<Result> _filteredList;
Future<PurchaseReport> _PurchaseReportResponse;
List<UsageResult> _usageList = [];
UsageResult _usageVal;
ScrollController _sc = new ScrollController();
bool isLoading = false;
//List users = new List();
#override
void initState() {
this._getMorePurchase(page);
super.initState();
_sc.addListener(() {
if (_sc.position.pixels ==
_sc.position.maxScrollExtent) {
_getMorePurchase(page);
}
});
}
#override
void dispose() {
_sc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Lazy Load Large List"),
),
body: Container(
child: _buildList(),
),
resizeToAvoidBottomInset: false,
);
}
Widget _buildList() {
return ListView.builder(
itemCount: _List.length + 1, // Add one more item for progress indicator
padding: EdgeInsets.symmetric(vertical: 8.0),
itemBuilder: (BuildContext context, int index) {
if (index == _List.length) {
return _buildProgressIndicator();
} else {
return new ListTile(
leading: CircleAvatar(
radius: 30.0,
),
title :Text("my:"+(_List[index]
.product)),
subtitle: Text((_List[index]
.unitPrice)),
);
}
},
controller: _sc,
);
}
Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isLoading ? 1.0 : 00,
child: new CircularProgressIndicator(),
),
),
);
}
Future<PurchaseReport> getProjectDetails() async {
var result = await PurchaseReportRequest(
context,
widget.userDetails.result.raLoginId,
limit.toString(),
offset.toString(),
fromDate,
toDate,
_usageVal!=null ? _usageVal.name : "" ,
);
return result;
}
void _getMorePurchase(int index) async {
if (!isLoading) {
setState(() {
isLoading = true;
});
_PurchaseReportResponse = getProjectDetails();
setState(() {
isLoading = false;
_PurchaseReportResponse.then((response) {
if (response != null) {
_List.addAll(response.result);
page = page + limit;
print("printing length : "
+_List.length.toString());
for (int i = 0; i < response.result.length; i++) {
print('name:' +_List[i].product );
}
} else {
errorRaisedToast(context);
}
});
});
}
}
}
Try This,
if (response != null) {
List newList = new List();
// _List.addAll(response.result);
page = page + limit;
print("printing length : "
+_List.length.toString());
for (int i = 0; i < response.result.length; i++) {
newList.add(response.result[i]);
print('name:' +_List[i].product);
}
isLoading = false;
_List.addAll(newList);
page++;
} else {
errorRaisedToast(context);
}

Flutter bool name = String its possible?

Hey i make a Favorite System with a bool to say if is favorite or not.
But if the name of the bool is always the same it applies to all my entries!
but each entry has its own name (widget.name), and i thought maybe something like that could work
bool widget.name;
but this not work :(
how can i solve that each entry has its own bool?
by the way i use this plugin for that
https://pub.dev/packages/shared_preferences/example
SharedPreferences sharedPreferences;
bool isfavorit;
#override
void initState() {
super.initState();
SharedPreferences.getInstance().then((SharedPreferences sp) {
sharedPreferences = sp;
isfavorit = sharedPreferences.getBool(spKey);
// will be null if never previously saved
if (isfavorit == null) {
isfavorit = false;
persist(isfavorit); // set an initial value
}
setState(() {});
});
}
void persist(bool value) {
setState(() {
isfavorit = value;
});
sharedPreferences?.setBool(spKey, value);
}
Complete Code
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Details extends StatefulWidget {
final String name;
Details(
this.name,
);
#override
_DetailsState createState() => _DetailsState();
}
const String spKey = 'myBool';
class _DetailsState extends State<Details> {
SharedPreferences sharedPreferences;
bool isfavorit;
#override
void initState() {
super.initState();
SharedPreferences.getInstance().then((SharedPreferences sp) {
sharedPreferences = sp;
isfavorit = sharedPreferences.getBool(spKey);
// will be null if never previously saved
if (isfavorit == null) {
isfavorit = false;
persist(isfavorit); // set an initial value
}
setState(() {});
});
}
void persist(bool value) {
setState(() {
isfavorit = value;
});
sharedPreferences?.setBool(spKey, value);
}
// ignore: missing_return
IconData favicon() {
if (isfavorit == true) {
return Icons.favorite;
} else if (isfavorit == false) {
return Icons.favorite_border;
}
}
// ignore: missing_return
Color favicolor() {
if (isfavorit == true) {
return Colors.red;
} else if (isfavorit == false) {
return Colors.white;
}
}
void changefav() {
if (isfavorit == true) {
return persist(false);
} else if (isfavorit == false) {
return persist(true);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
favicon(),
color: favicolor(),
),
onPressed: () => changefav(),
),
],
title: Text(widget.name),
),
body: Container(
child: Text(widget.name),
),
);
}
}
You are always saving the isFavorite to the same key in shared preferences, instead of using a constant key use one that is based on the widget.name
So for instance:
sharedPreferences.getBool('details_favorite_${widget.name}');