如何让消费者在颤振中听到多个参数?



我需要让消费者小部件根据布尔值侦听多个变量。

这是模型类

class Lawyer{
Data? data;
double? distance = 0;
Lawyer({this.data, this.distance});
factory Lawyer.fromJson(Map<String, dynamic> json) =>
Lawyer(data: Data.fromJson(json['listing_data']));
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////

class Data{
String? title;
String? email;
String? phone;
Location? location;
List<String>? logo;
List<String>? cover;
Data({this.title, this.email, this.phone, this.logo, this.cover, this.location});
factory Data.fromJson(Map<String, dynamic> json) {
var logo = json['_job_logo'];
var cover = json['_job_cover'];
var long = json['geolocation_long'];
var lat = json['geolocation_lat'];
return Data(title: json['_job_tagline'], email: json['_job_email'],
location: Location(latitude: json['geolocation_lat'], longitude: json['geolocation_long']),
phone: json['_job_phone'], logo: List<String>.from(logo),
cover: List<String>.from(cover)
);
}
}

这是视图模型通知器

class LawyerAPIServices extends ChangeNotifier{
final url = "https://dalilvision.com/wp-json/wp/v2/job_listing";      
List<Lawyer> lawyersList = [];
List<Lawyer> staticLawyersList = [];

Future<List<Lawyer>> fetchLawyers() async{
final response = await get(Uri.parse(url.toString()));
if(response.statusCode == 200){
var dynamicLawyersList = jsonDecode(response.body);
print('$dynamicLawyersList');
lawyersList = List<Lawyer>.from(dynamicLawyersList.map((x) => Lawyer.fromJson(x)));
staticLawyersList = lawyersList;
lawyersList.forEach((element) {print('all lawyers: ${element.data!.location}');});
notifyListeners();
return lawyersList;
}
else{
notifyListeners();
throw Exception(response.statusCode);
}
}

Future<List<Lawyer>> getFullListOfLawyers() async {
notifyListeners();
print('fulll list: ${staticLawyersList.length}');
return staticLawyersList;
}
}

最后是消费者小部件

Consumer<LawyerAPIServices>(
builder: (context, value, child) => FutureBuilder(
future: _list,
builder: (BuildContext context, AsyncSnapshot<List<Lawyer>> snapshot) {
if (snapshot.hasData){
return ListView.separated(
physics: const NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
separatorBuilder: (context, index) => const Divider(color: Colors.transparent),
itemCount: value.lawyersList.length,
itemBuilder: (context, index) {
return InkWell(
child: LawyerWidget(
title: snapshot.data![index].data!.title!,
email: snapshot.data![index].data!.email!,
phone: snapshot.data![index].data!.phone!,
logo: snapshot.data![index].data!.logo![0],
cover: snapshot.data![index].data!.cover![0]
),
);
}
}
);
}
else if(snapshot.hasError){
return Center(
child: Text(snapshot.error.toString())
);
}
else {
return const CircularProgressIndicator(
strokeWidth: 2,
);
}
},
),
)

在通知器class中有两个列表,staticLawyerList仅在从网络调用获取列表时初始化一次,然后用作备份列表,lawyersList是将被操纵的列表。

到目前为止,我所做的是通过网络调用获得lawyersList的初始值,然后不知何故,staticLawyersList的值总是等于lawyersList,即使我做了任何更改或操纵lawyersList,这些更改也会自动反映在staticLawyersList上,这真的很奇怪。

现在我想要实现的是应用一个条件,根据这个条件用适当的列表更新UI。

if(setByPosition == false){
//update UI with `staticLawyersList`
}
else {
//update UI with `lawyersList` 
}

更新! !

下面是我如何更新我的consumer

CheckboxListTile(
activeColor: Colors.black,
value: isChecked,
onChanged: (value) async {
saveSharedPreferences(value: value!);
if(value == true) {
Provider.of<LawyerAPIServices>(context, listen: false).sortLawyersList(
devicePosition: widget.position, lawyersList: widget.list);
}
else{
Provider.of<LawyerAPIServices>(context, listen: false).getFullListOfLawyers();// the list returned by this function don't applied to the consumer
}
setState(() {
isChecked = value;
Navigator.pop(context);
});
},
title: const Text('Filter by distance'),
),

需要考虑的几点:

  1. 当你这样做时&;staticLawyersList = lawyerslist &;实际上你有两个指针到同一个列表。它对列表、集合、类等都是这样工作的。只有基本类型如int, double, string被真正复制。你可以用这个代替:"staticLawyersList = List.from(lawyersList);">

  2. 看起来你不需要在lawyerapisservices中使用ChangeNotifier。您可以在需要的小部件中创建lawyerapisservices的实例,并调用fetchLawyers。如果不想多次重建列表,请在StatefullWidget的initState中执行此操作。在你的构建方法中,使用FutureBuilder来读取Future并决定在UI中显示什么。

class _MyWidget extends State<MyWidget> {
late final LawyerAPIServices lawyerApi;

// Create this variable to avoid calling fetchLawers many times
late final Future<List<Lawyer>> lawyersList;

@override
void initState() {
super.initState();
// Instantiate your API
lawyerApi = LawyerAPIServices();

// This will be called only once, when this Widget is created
lawyersList = lawyerApi.fetchLawyers();
}

@override
Widget build(BuildContext context) {
return FutureBuilder<List<Lawyer>>(
future: lawyersList,
builder: ((context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
if (setByPosition) {
//update UI with `lawyersList`
return _listView(snapshot.data!);
} else {
//update UI with `staticLawyersList`
// Since the Future state is Complete you can be sure that
// the staticLawyersList variable in your API was already set
return _listView(lawyerApi.staticLawyersList);
}
case ConnectionState.none:
return const Text('Error');
default:
return const CircularProgressIndicator.adaptive();
}
}),
);
}

Widget _listView(List<Lawyer> lawyersList) {
return ListView.separated(
physics: const NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
separatorBuilder: (context, index) =>
const Divider(color: Colors.transparent),
itemCount: lawyersList.length,
itemBuilder: (context, index) {
return InkWell(
child: LawyerWidget(
title: lawyersList[index].data!.title!,
email: lawyersList[index].data!.email!,
phone: lawyersList[index].data!.phone!,
logo: lawyersList[index].data!.logo![0],
cover: lawyersList[index].data!.cover![0]),
);
});
}
}
  1. 如果出于任何原因你需要在多个小部件之间共享相同的LawyerAPIServices,你可以在树的顶部实例化它,并使用Provider或作为参数发送它。

  2. 方法getfulllistayyers不需要返回一个Future,因为staticLawyersList是一个List(不是Future)。你可以使用" lawyerapisservices . staticlawyerslist "或者像这样的东西可能有意义:

    Futuregetfulllistayers () async {如果(staticLawyersList.isEmpty) {等待fetchLawyers ();}print('完整列表:${staticLawyersList.length}');返回Future.value (staticLawyersList);}

正如@ saicchi - okuma所说,要复制列表的内容,您应该使用staticLawyersList = List.from(lawyersList),因为在dart和大多数java编译器编程语言中,当您使用staticLawyersList = lawyersList时,这意味着您通过staticLawyersList引用lawyersList。然后我在staticLawyersList

的帮助下按我想要的操作lawyersList
lawyersList.clear();
lawyersList.addAll(staticLawyersList);

但是当我这样做时,消费者没有应用基于staticLawyersList的更改,尽管logcat显示staticLawyersList长度为10,这是我想要的(完整列表,不过滤)。

我的问题可以归纳为两点:

1-消费者只听一个列表lawyersList,我认为它仍然存在。2- @Saichi-Okuma提到的指针问题。

这里是完整的代码更改

void getFullListOfLawyers() {
lawyersList.clear(); // to make sure that the list is clean from older operations
lawyersList.addAll(staticLawyersList);// the trick
notifyListeners();

}

Future<List<Lawyer>> fetchLawyers() async{
final response = await get(Uri.parse(url.toString()));
if(response.statusCode == 200){
var dynamicLawyersList = jsonDecode(response.body);
print('$dynamicLawyersList');
lawyersList = List<Lawyer>.from(dynamicLawyersList.map((x) => Lawyer.fromJson(x)));
staticLawyersList = List.from(lawyersList);// use this statment instead of staticLawyersList = lawyersList
lawyersList.forEach((element) {print('all lawyers: ${element.data!.location}');});
notifyListeners();
return lawyersList;
}
else{
notifyListeners();
throw Exception(response.statusCode);
}

}

无论列表的状态如何,每次调用notifyListeners时,都会重新构建Consumer Widget。

可能您没有访问正在使用的API的实例。请确保您正在使用Consumer构建器的第二个参数。

Consumer<LawyerAPIServices>(builder: (context, lawyerAPI, child) => 
FutureBuilder(
future: lawyerAPI.fetchLawyers(),
builder: ((context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
if (setByPosition) {
//update UI with `lawyersList`
return _listView(snapshot.data!);
} else {
//update UI with `staticLawyersList`
// Since the Future state is Complete you can be sure that
// the staticLawyersList variable in your API was already set
return _listView(lawyerAPI.staticLawyersList);
}
case ConnectionState.none:
return const Text('Error');
default:
return const CircularProgressIndicator.adaptive();
}
}),

我认为你不需要下面的代码来满足这个特殊的需求。它会覆盖你的lawyersList并通知所有的听众,即使实际上什么都没有改变。只要直接访问你的staticLawyersList,因为它是在你调用fetchLawyers时填充的。

void getFullListOfLawyers() {
lawyersList.clear(); // to make sure that the list is clean from older operations
lawyersList.addAll(staticLawyersList);// the trick
notifyListeners();
}

最新更新