シングルトンによるデータストアの実装
アプリケーションワイドにデータを持つシングルトンの作成方法を紹介します。
Dart にはシングルトン作成用の仕組みがあります。コンストラクタに factory とマークすることによって、 オブジェクトを常に作成するのではなく、もしキャッシュがあればそれを使う、という動作を実装できます。
item_store.dart として次を作成します。
class ItemStore {
static final Map<dynamic, dynamic> _item = <dynamic, dynamic>{};
static final ItemStore _cache = ItemStore._internal();
factory ItemStore() {
return _cache;
}
ItemStore._internal();
set(dynamic key, dynamic value) => _item[key] = value;
get(dynamic key) => _item[key];
}
ここでは _cache という変数に、一度作成したオブジェクト (インスタンス) を保持しており、 factory とマークされたコンストラクタではそれを常に返しています。
これを利用する側は、これがシングルトンであるかどうかを意識することなく、通常通りコンストラクタを呼び出すことで、 毎回同じオブジェクトを利用することができます。
_internal() としている箇所は、コンストラクタをプライベートアクセスにしているところです。 _internal() という名前は慣例的なものであって、必ずしもこの名前である必要はありません。極端な話 _() などでも構いません。
ここで作成するテストプログラムは次のようになります。
最初の画面 HomePage で名前を入力したら、次の画面でそれを表示しています。
このスクリーン遷移をまたいでデータを受け渡しするのに、シングルトンで実装したデータストアを利用しています。
最初のページは次のような実装になります。
pages/home.dart
import 'package:flutter/material.dart';
import 'package:test30_globalstore/item_store.dart';
class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Container(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Username',
icon: Icon(Icons.account_box),
),
),
RaisedButton(
child: Text('Next'),
onPressed: () {
ItemStore().set('name', _controller.text);
Navigator.of(context).pushNamed('/second');
},
),
],
),
),
);
}
}
二番目の画面を pages/second.dart として次とします。
import 'package:flutter/material.dart';
import '../item_store.dart';
class SecondPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _SecondPageState();
}
}
class _SecondPageState extends State<SecondPage> {
String _name;
@override
void initState() {
_name = ItemStore().get('name');
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second'),
),
body: Center(
child: Container(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(20),
child: Text(
'Hello, $_name!',
style: TextStyle(fontSize: 20),
),
),
RaisedButton(
child: Text('Back'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
),
),
);
}
}
この上で、main.dart を次とします。
main.dart
import 'package:flutter/material.dart';
import './pages/home.dart';
import './pages/second.dart';
void main() => runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
routes: <String, WidgetBuilder>{
'/home': (BuildContext context) => HomePage(),
'/second': (BuildContext context) => SecondPage()
},
),
);
以上、ここでは Dart でシングルトンを実装する方法と、それを利用する方法について説明しました。