使用 FutureBuilder 时,Mobx Observer 无法按预期工作

Mobx Observer not working as expected when using FutureBuilder

当尝试在脚手架主体内创建项目的列表视图时,我无法使用 mobx(版本:0.3.5)在另一个地方(Appbar)更新该列表中项目数量的显示和 flutter_mobx(版本:0.3.0+1)。

我已经尝试使用 Provider 包 (3.0.0+1) 解决这个问题,但这也没有解决,所以我想我遗漏了一些关于 FutureBuilder 和 Flutter 构建过程的本质.

// the mobx-store
ItemTracker itemTracker = ItemTracker();

class StartPage extends StatefulWidget {
  StartPageState createState() => StartPageState();
}

class StartPageState extends State<StartPage> {
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
// this Observer doesn't update
          leading: Observer(
              builder: (_) => Text('Items: ' + itemTracker.amount.toString())),
          title: Text('MyApp',
              style: TextStyle(
                color: Colors.deepPurpleAccent[50],
                fontSize: 16,
                fontWeight: FontWeight.bold,
              )),
          centerTitle: true,
        ),
        body: ListView(
          shrinkWrap: true,
          padding: const EdgeInsets.all(20.0),
          children: <Widget>[
            FutureBuilder(
                future: ApiService.getOffers(),
                builder: (BuildContext context,
                    AsyncSnapshot<List<Offer>> snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.none:
                    case ConnectionState.waiting:
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                    default:
                      return snapshot.hasError
                          ? Text('Error: ${snapshot.error}')
                          : _createOfferList(context, snapshot);
                  }
                }),
          ],
        ),
      ),
    );
  }
  Widget _createOfferList(BuildContext context, AsyncSnapshot snapshot) {
// after receiving the response, the amount of items should get written to 
// itemTracker.amount - the Observer-part should be rerendered, but it won't
    itemTracker.updateAmount(snapshot.data.length);
    print(snapshot.data.length.toString());
    return ListView.builder(
        itemCount: snapshot.data.length,
        shrinkWrap: true,
        primary: false,
        itemBuilder: (BuildContext context, int index) {
          return Card(
              color: Colors.lightBlue[50],
              child: ListTile(
                leading: Image.asset(snapshot.data[index].image),
                title: Text(snapshot.data[index].name),
                subtitle: Text(snapshot.data[index].description ?? ''),
                isThreeLine: true,
                trailing: Padding(
                  padding: EdgeInsets.only(top: 8.0, right: 4.0),
                  child: Icon(
                    Icons.explore,
                    color: Colors.green[200],
                    size: 30,
                  ),
                ),
                onTap: () => Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) =>
                            OfferDetailPage(snapshot.data[index]))),
              ));
        });
  }
}

所以代码的上半部分从 ApiService.getOffers 中获取项目,然后调用 _createOfferList 来构建 Listview。 在这个方法中,itemTracker-实例的 mobx-observable amount 被 mobx-action updateAmount(int newValue) 更新为快照数据列表的长度。
在上面的 Scaffold 中,我然后使用 Observer 来跟踪和显示项目的数量。
除了未更新的数量之外,该应用程序按预期工作并且列表得到呈现。如果我在应用程序中前后导航,列表项的数量会正确显示,但它永远不会发生在初始页面加载时。

edit:作为旁注:我没有炫耀 ItemTracker class-定义和相应生成的 class,因为它所做的只是为 amount-成员使用一个可观察注释,为只接受一个 int 参数并将其写入 this.amount.[=22 的方法使用一个动作注释=]

所以今天我设法解决了我的问题,引入了一个持有物品的 class 成员,并通过在 initState()- 中调用 itemTracker.updateAmount() 对收到物品做出反应方法。

class OfferPage extends StatefulWidget {
  final Future<List<Offer>> data = ApiService.getOffers();
  OfferPageState createState() => OfferPageState();
}

class OfferPageState extends State<OfferPage> {
  @override
  void initState() {
    widget.data.then((offers) => itemTracker.updateAmount(offers.length));
    super.initState();
  }
// ...

//the new Scaffold body part
body: ListView(
          shrinkWrap: true,
          padding: const EdgeInsets.all(20.0),
          children: <Widget>[
            FutureBuilder(
// no longer create a request, but instead use the existing request's future
                future: widget.data,
                builder: (BuildContext context, AsyncSnapshot snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.none:
                    case ConnectionState.waiting:
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                    default:
                      return _createOfferList(context, snapshot);
                  }
                }),
          ],
        ),

_createOfferList-方法保持完全相同,尽管没有调用 updateAmount(),因为这部分现在在 initState().

中处理