我正在按照this tutorial中描述的模式,使用Provider(3.1.0)中的MultiProvider构建一个flutter应用程序。
在我的主页中,我想加载配置数据(地点货币符号),但不显示模型。我在上面链接的教程中使用了类似于登录服务的模式,但是当我尝试在另一个视图(清单)中使用值Provider.of(context).currency
时,出现此错误。
以下NoSuchMethodError被抛出
BillListItem(脏,依赖项:[InheritedProvider]):
getter'currency'在null上被调用。接收方:null尝试调用:
货币
我不知道与获得Provider.of (上下文).name
的登录名有何不同
这是我的代码:
main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: providers,child: MaterialApp(
title: 'Flutter Demo',theme: ThemeData(
primarySwatch: Colors.blue,),initialRoute: RoutePaths.Login,onGenerateRoute: Router.generateRoute,);
}
}
我要在其中使用提供程序值的视图。
class BillListItem extends StatelessWidget {
final Bill bill;
final Function onTap;
const BillListItem({this.bill,this.onTap});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,child: Container(
margin: EdgeInsets.symmetric(horizontal: 20.0,vertical: 15.0),padding: EdgeInsets.all(10.0),decoration: BoxDecoration(
color: Colors.white,borderRadius: BorderRadius.circular(5.0),boxShadow: [
BoxShadow(
blurRadius: 3.0,offset: Offset(0.0,2.0),color: Color.fromARGB(80,0))
]),child: Column(
crossAxisAlignment: CrossAxisAlignment.start,children: [
Text(bill.billNumber.toString(),style: TextStyle(fontWeight: FontWeight.w900,fontSize: 16.0),Text("${Provider.of(context).currency}${bill.payable.toString()}",],);
}
}
我在其中注入场地的选项卡视图:
class tabcontainer extends StatefulWidget {
@override
State createState() => tabcontainerState();
}
class tabcontainerState extends State {
@override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => _fetchVenue(context));
}
@override
Widget build(BuildContext context) {
return BaseWidget(
model: VenueModel(venueService: Provider.of(context)),builder: (context,model,child) => DefaultTabController(
length: 2,child: Scaffold(
appBar: AppBar(
bottom: TabBar(
isScrollable: false,tabs: [
Tab(icon: Icon(Icons.home)),Tab(icon: Icon(Icons.room_service)),centerTitle : true,title: Text('Exact POS'),actions: [
FutureBuilder(
future: SharedPreferencesHelper.getLanguagecode(),initialData: 'en',builder: (BuildContext context,Asyncsnapshot snapshot) {
return snapshot.hasData
? Buildflag.buildflag(context,snapshot.data)
: Container();
}
),]
),body: SafeArea(
child: TabBarView(
children: [
HomeView(),LoginView(),)
)
);
}
void _fetchVenue(BuildContext context) async {
Api _api = new Api();
VenueService _venueService = new VenueService(api: _api);
VenueModel _venueModel = new VenueModel(venueService: _venueService);
var success = await _venueModel.fetchVenue();
}
}
home_view.dart
。我怀疑这可能是我需要注入Venue
提供程序的地方,而不是tabcontainer
中的地方。
class HomeView extends StatefulWidget{
@override
State createState() => HomeViewState();
}
class HomeViewState extends State {
@override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => showsnackBar());
}
void showsnackBar(){
Scaffold.of(context).showsnackBar(snackBar(
content: Text('Welcome ${Provider.of(context).name}',style: snackBarStyle),backgroundColor: snackBarColor,duration: Duration(seconds: 4),));
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: backgroundColor,body: Column(
crossAxisAlignment: CrossAxisAlignment.start,children: [
UIHelper.verticalSpaceSmall,Expanded(
child: Tables(),)
],)
);
}
}
我的视图模型VenueModel
class VenueModel extends BaseModel {
VenueService _venueService;
VenueModel(
{@required VenueService venueService,}
) : _venueService = venueService;
Future fetchVenue() async {
setBusy(true);
var success = await _venueService.fetchVenue();
setBusy(false);
return success;
}
}
我的服务VenueService
class VenueService {
final Api _api;
VenueService({Api api}) : _api = api;
StreamController _venueCOntroller= StreamController();
Stream get venue => _venueController.stream;
Future fetchVenue() async {
var fetchedVenue = await _api.getVenue();
var hasVenue = fetchedVenue != null;
if (hasVenue) {
_venueController.add(fetchedVenue);
}
return hasVenue;
}
}
我的BaseModel.dart
class BaseModel extends ChangeNotifier {
bool _busy = false;
bool get busy => _busy;
void setBusy(bool value) {
_busy = value;
notifyListeners();
}
}
我的提供商设置代码:
List providers = [
...independentServices,...dependentServices,...uiConsumableProviders
];
List independentServices = [
Provider.value(value: Api())
];
List dependentServices = [
ProxyProvider(
builder: (context,api,authenticationService) => AuthenticationService(api: api),ProxyProvider(
builder: (context,venueService) => VenueService(api: api),];
List uiCOnsumableProviders= [
StreamProvider(
builder: (context) => Provider.of(context,listen: false).user,StreamProvider(
builder: (context) => Provider.of(context,listen: false).venue,];
base_widget.dart
class BaseWidget extends StatefulWidget {
final Widget Function(BuildContext context,T model,Widget child) builder;
final T model;
final Widget child;
final Function(T) onmodelReady;
BaseWidget({
Key key,this.builder,this.model,this.child,this.onmodelReady,}) : super(key: key);
_BaseWidgetState createState() => _BaseWidgetState();
}
class _BaseWidgetState extends State> {
T model;
@override
void initState() {
model = widget.model;
if (widget.onmodelReady != null) {
widget.onmodelReady(model);
}
super.initState();
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
builder: (context) => model,child: Consumer(
builder: widget.builder,child: widget.child,);
}
}
以下NoSuchMethodError被抛出
BillListItem(脏,依赖项:[InheritedProvider]):获取程序
在null上调用了“ currency”。接收方:null尝试通话:货币
此错误表示Provider.of(context)
返回null
。这可能是由于两个原因:
将-
null
值添加到VenueService
中的流中。对于您的代码,情况并非如此,这使我相信这是第二个原因:
-
VenueService
中的流没有发出任何值,因此流的初始数据为null
浏览完代码后,只有在标签视图中才调用fetchVenue
中的VenueService
:
WidgetsBinding.instance.addPostFrameCallback((_) => _fetchVenue(context));
void _fetchVenue(BuildContext context) async {
Api _api = new Api();
VenueService _venueService = new VenueService(api: _api);
VenueModel _venueModel = new VenueModel(venueService: _venueService);
var success = await _venueModel.fetchVenue();
}
在您的_fetchVenue
函数中,您实际上是在创建Api
,VenueService
和VenueModel
的新实例,而这些实例在应用程序的其他任何地方都不会被使用。提供者列表中的实际VenueService
保持不变。实际的fetchVenue
中的VenueService
函数永远不会被调用,这就是Provider.of(context)
返回null
的原因,因为流没有值。
因此,您可以将_fetchVenue
函数替换为此:
void _fetchVenue(BuildContext context) async {
VenueService _venueService = Provider.of(context);
VenueModel _venueModel = new VenueModel(venueService: _venueService);
var success = await _venueModel.fetchVenue();
}
仍然需要进行一些改进,例如_venueModel
并未在任何地方使用,但我希望这可以解决您的问题!