[英]Flutter - How does MultiProvider work with providers of the same type?
例如,我試圖一次獲取為多個流發出的數據,但是這些流中的 2 個或更多發出相同類型的數據,比如說一個字符串。
我的問題是,是否可以使用MultiProvider
並使用相同類型的多個StreamProvider
(或任何提供者,但我對這種情況感興趣),同時仍然能夠訪問每個提供者發出的數據?
一個解決方案是在使用常見數據類型時使用StreamBuilder
,但我真的很喜歡MultiProvider
在更清晰的代碼方面提供的功能。
例子:
class MyScreen extends StatelessWidget {
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<String>(stream: Observable.just("stream1")),
StreamProvider<String>(stream: Observable.just("stream2")),
StreamProvider<String>(stream: Observable.just("stream3"))
],
child: Builder(
builder: (BuildContext context) {
AsyncSnapshot<String> snapshot =
Provider.of<AsyncSnapshot<String>>(context);
String data = snapshot.data;
return Text(data);
},
),
);
}
}
MultiProvider
與否不會改變任何東西。 如果兩個提供程序共享相同的類型,則最深的一個會覆蓋該值。
不可能從不是給定類型最接近祖先的提供者那里獲取值。
如果您需要獨立訪問所有這些值,則每個值都應具有唯一的類型。
例如,而不是:
Provider<int>(
value: 42,
child: Provider<int>(
value: 84,
child: <something>
),
)
你可以做:
class Root {
Root(this.value);
final int value;
}
class Leaf {
Leaf(this.value);
final int value;
}
Provider<Root>(
value: Root(42),
child: Provider<Leaf>(
value: Leaf(84),
child: <something>
),
)
這允許使用以下方法獨立獲取每個值:
Provider.of<Root>(context)
Provider.of<Leaf>(context);
更新:我最近發現的這個解決方案似乎更干凈,工作得更好。 下面的解決方案是另一種方式,但需要更多的編碼。
我一直在尋找類似的解決方案,但找不到任何解決方案,因此我使用 MultiProvider、StreamGroup 和 ChangeNotifier 實現了自己的解決方案。 我使用StreamGroup
來保存我需要通過添加和刪除流來跟蹤的所有流。 我不想使用一堆額外的庫和/或插件。
在ChangeNotifierProxyProvider
,只要Family
流從其上方的StreamProvider<Family>
獲得更新,它就會運行update
函數。
// main.dart
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<Family>(
initialData: Family(),
create: (context) => FirebaseFireStoreService().streamFamilyInfo(),
),
ChangeNotifierProxyProvider<Family, FamilyStore>(
create: (context) => FamilyStore(),
update: (context, family, previousFamilyStore) {
// Manually calling the function to update the
// FamilyStore store with the new Family
previousFamilyStore!.updateFamily(family);
return previousFamilyStore;
},
)
],
builder: (context, child) => MaterialApp(),
);
}
Family
只保存了一個AdultProfile
uid
數組,所以我可以跟蹤一個家庭中的成年人。 它基本上只是一個流接收器。
// family.dart
class Family {
List<String> adults;
Family({
this.adults = const [],
});
factory Family.fromMap(Map<String, dynamic>? data) {
if (data == null) {
return Family(adults: []);
}
return Family(
adults: [...data['adults']],
);
}
}
在我的 firestore class
,我有必要的函數可以為我需要的class
返回一個Stream
。 我只粘貼了Family
的函數,但為AdultProfile
粘貼了相同的代碼,但路徑變化很小。
// firebase_firestore.dart
Stream<Family> streamFamilyInfo() {
try {
return familyInfo(FirebaseAuthService().currentUser!.uid).snapshots().map(
(snapshot) {
return Family.fromMap(snapshot.data() as Map<String, dynamic>);
},
);
} catch (e) {
FirebaseAuthService().signOut();
rethrow;
}
}
這是大部分工作發生的地方:
// family_store.dart
class FamilyStore extends ChangeNotifier {
List<AdultProfile>? adults = [];
StreamGroup? streamGroup = StreamGroup();
FamilyStore() {
// Handle the stream as they come in
streamGroup!.stream.listen((event) {
_handleStream(event);
});
}
void handleStream(streamEvent) {
// Deal with the stream as they come in
// for the different instances of the class
// you may have in the data structure
if (streamEvent is AdultProfile) {
int index = adults!.indexWhere((element) => element.uid == streamEvent.uid);
if (index >= 0) {
adults![index] = streamEvent;
} else {
adults!.add(streamEvent);
}
notifyListeners();
}
// This is the function called from the
// ChangeNotifierProxyProvider in main.dart
void updateFamily(Family newFamily) {
_updateAdults(newFamily.adults);
}
void _updateAdults(List<String> newAdults) async {
if (newAdults.isEmpty) return;
// Generate list of comparisons so you can add/remove
// streams from StreamGroup and the array of classes
Map<String, List<String>> updateLists =
_createAddRemoveLists(adults!.map((profile) => profile.uid).toList(), newAdults);
for (String uid in updateLists['add']!) {
// Add the stream for the instance of the
// AdultProfile to the StreamGroup
(streamGroup!.add(
FirebaseFireStoreService().streamAdultProfile(uid),
));
}
for (String uid in updateLists['remove']!) {
// Remove the stream for the instance of the
// AdultProfile from the StreamGroup
streamGroup!.remove(
FirebaseFireStoreService().streamAdultProfile(uid),
);
// Also remove it from the array
adults!.removeWhere((element) => element.uid == uid);
notifyListeners();
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.