問題:
次のように、Default Tabs Controller を使用するタブが 2 つあります。
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
drawer: Menu(),
appBar: AppBar(
title: Container(
child: Text('Dashboard'),
),
bottom: TabBar(
tabs: <Widget>[
Container(
padding: EdgeInsets.all(8.0),
child: Text('Deals'),
),
Container(
padding: EdgeInsets.all(8.0),
child: Text('Viewer'),
),
],
),
),
body: TabBarView(
children: <Widget>[
DealList(),
ViewersPage(),
],
),
),
);
}
}
は次のように構築されDealList()
ますStatefulWidget
。
Widget build(BuildContext context) {
return FutureBuilder(
future: this.loadDeals(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print('Has error: ${snapshot.hasError}');
print('Has data: ${snapshot.hasData}');
print('Snapshot data: ${snapshot.data}');
return snapshot.connectionState == ConnectionState.done
? RefreshIndicator(
onRefresh: showSomething,
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: snapshot.data['deals'].length,
itemBuilder: (context, index) {
final Map deal = snapshot.data['deals'][index];
print('A Deal: ${deal}');
return _getDealItem(deal, context);
},
),
)
: Center(
child: CircularProgressIndicator(),
);
},
);
}
}
上記の場合、タブに戻るたびに次のことが起こりますDealList()
: タブが再読み込みされます。
一度実行したら FutureBuilder の再実行を防ぐ方法はありますか? (計画では、ユーザーは RefreshIndicator を使用してリロードします。したがって、ユーザーが明示的に変更しない限り、タブを変更しても何もトリガーされません。)
ベストアンサー1
ここでは 2 つの問題があります。1 つ目は次のとおりです。
タブを切り替えるとTabController
、メモリを節約するために古いウィジェットツリーをアンロードします。この動作を変更したい場合は、ミックスインする必要があります。AutomaticKeepAliveClientMixin
タブウィジェットの状態。
class _DealListState extends State<DealList> with AutomaticKeepAliveClientMixin<DealList> {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context); // need to call super method.
return /* ... */
}
}
2 番目の問題は、 の使用方法にあります。にFutureBuilder
新しい を提供すると、結果が前回と同じになるかどうかがわからないため、再構築する必要があります。(Flutter はフレームごとに最大 1 回、ビルド メソッドを呼び出す場合があることに注意してください)。Future
FutureBuilder
return FutureBuilder(
future: this.loadDeals(), // Creates a new future on every build invocation.
/* ... */
);
代わりに、initState で State クラスのメンバーに future を割り当て、この値を に渡します。 は、後続の再構築で future が同じになることを保証します。 State に取引を強制的に再ロードさせたい場合は、いつでもメンバーを再割り当てして を呼び出すFutureBuilder
メソッドを作成できます。_loadingDeals
setState
Future<...> _loadingDeals;
@override
void initState() {
_loadingDeals = loadDeals(); // only create the future once.
super.initState();
}
@override
Widget build(BuildContext context) {
super.build(context); // because we use the keep alive mixin.
return new FutureBuilder(future: _loadingDeals, /* ... */);
}