我正在尝试使用flutter和Marvel API创建一个简单的英雄个人资料应用程序。对于状态管理,我使用提供程序包和带流的bloc策略。 我创建了一个小部件,该小部件是我的搜索栏,用户将在其中输入英雄的名字,每当用户单击“提交”按钮或提交表单时,便在其中添加了对CharacterProfileFormProvider queryCharacter方法的调用。在queryCharacter方法中,调用访问API并返回英雄的服务类。
通话代码:
onFieldSubmitted: (value) async {
if (_formKey.currentState.validate()) {
await characterProfileFormProvider
.queryCharacter(characterNameController.text);
}
}
queryCharacter方法的代码:
queryCharacter(String characterName) async {
Character character = await characterService.show(characterName);
characterProfileProvider.changeCharacter(character);
}
API调用的代码:
Future<Character> show(String characterName) async {
String url = this.baseUrl + '/$resource';
Map<String, dynamic> query = this.makeQueryParams();
query['name'] = characterName;
Character character;
try {
Response response = await Dio().get(url, queryParameters: query);
character = Character.fromJson(jsonDecode(response.toString()));
} catch (e) {
character = Character(
id: 1009368,
name: 'Iron Man Test',
description:
"Wounded, captured and forced to build a weapon by his enemies, billionaire industrialist Tony Stark instead created an advanced suit of armor to save his life and escape captivity. Now with a new outlook on life, Tony uses his money and intelligence to make the world a safer, better place as Iron Man.",
thumbnailPath:
'http://i.annihil.us/u/prod/marvel/i/mg/9/c0/527bb7b37ff55/standard_xlarge.jpg',
comics: 2554,
series: 623,
stories: 3875,
events: 31,
);
}
return character;
}
返回API调用之后,结果将通过changeCharacter方法发送到CharacterProfileProvider,该方法在流中输入新字符并调用notifyListeners()方法。
changeCharacter方法的代码:
changeCharacter(Character character) {
print(character.name);
inputCharacter.add(character);
notifyListeners();
}
最后在屏幕上,我使用“消费者”小部件来获取新值,以在屏幕上呈现数据
使用数据的屏幕的代码:
import 'package:flutter/material.dart';
import 'package:marvel_api/src/models/Character.dart';
import 'package:marvel_api/src/pages/CharacterProfile/CharacterProfileProvider.dart';
import 'package:marvel_api/src/components/CharacterProfileForm/CharacterProfileForm.dart';
import 'package:provider/provider.dart';
import 'package:marvel_api/src/components/ImageResolver/ImageResolver.dart';
class CharacterProfile extends StatefulWidget {
@override
_CharacterProfileState createState() => _CharacterProfileState();
}
class _CharacterProfileState extends State<CharacterProfile> {
final TextStyle numberTitleStyle = TextStyle(
color: Colors.grey[300],
fontSize: 24.0,
);
final TextStyle numberValueStyle = TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 19.0,
);
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
color: Colors.red,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: <Widget>[
// Search Hero
Expanded(
child: CharacterProfileForm(),
flex: 1,
),
Expanded(
flex: 8,
child: Consumer<CharacterProfileProvider>(
builder: (context, characterProfileProvider, widget) {
return StreamBuilder<Character>(
stream: characterProfileProvider.outputCharacter,
initialData: Character(),
builder: (context, snapshot) {
print('Rebuild');
return SingleChildScrollView(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: <Widget>[
// Hero Thumbnail
Container(
child: Padding(
padding: EdgeInsets.only(bottom: 15.0),
child: ImageResolver(
image: snapshot.data.thumbnailPath,
),
),
),
// Hero Info
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
// Character Name:
Text(
'Name:',
style: TextStyle(
color: Colors.grey[300],
fontSize: 28.0,
),
),
Text(
snapshot.data.name,
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 7.0,
),
// Character Description:
Text(
'Description:',
style: TextStyle(
color: Colors.grey[300],
fontSize: 28.0,
),
),
Text(
snapshot.data.description,
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 7.0,
),
// Number of comics
Text(
'Number of comics:',
style: numberTitleStyle,
),
Text(
'$snapshot.data.comics',
style: numberValueStyle,
),
SizedBox(
height: 8.0,
),
// Number of series
Text(
'Number of series:',
style: numberTitleStyle,
),
Text(
'$snapshot.data.series',
style: numberValueStyle,
),
SizedBox(
height: 8.0,
),
// Number of stories
Text(
'Number of stories:',
style: numberTitleStyle,
),
Text(
'$snapshot.data.stories',
style: numberValueStyle,
),
SizedBox(
height: 8.0,
),
// Number of events
Text(
'Number of events:',
style: numberTitleStyle,
),
Text(
'$snapshot.data.events',
style: numberValueStyle,
),
SizedBox(
height: 8.0,
),
],
),
],
),
),
);
});
}),
),
],
),
),
),
),
);
}
}
这是我放置提供程序声明的地方:
import 'package:flutter/material.dart';
import 'package:marvel_api/src/pages/CharacterProfile/CharacterProfile.dart';
import 'package:marvel_api/src/pages/CharacterProfile/CharacterProfileProvider.dart';
import 'package:marvel_api/src/components/CharacterProfileForm/CharacterProfileFormProvider.dart';
import 'package:provider/provider.dart';
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => CharacterProfileFormProvider(),
),
ChangeNotifierProvider(
create: (_) => CharacterProfileProvider(),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: CharacterProfile(),
),
);
}
}
此外,所有provider类都从ChangeNotifier类扩展而来。
我的问题是,当调用notifyListener方法时,不会重建侦听器,我使用VS Code调试器确认了这一点,并且尝试使用Provider.of()来获得相同的结果。有人可以帮我还是告诉我我哪里错了。