FlutterのBLoCアーキテクチャを実装する
Flutterで有名なBLoCアーキテクチャの実装方法について紹介します。
BLoCとは
BLoCとはGoogleが推奨しているアーキテクチャになります。 詳しくは下記をご覧ください
こちらもすごく参考になるきじなのでこちらもどうぞ
今回はこれに発展してAPIを叩くような場合の実装をします。
構成
構成はこんな感じです。
パッケージ構成はこうします。
実装
それではソースコードを貼っていきます。
準備とUIScreenを実装します。
- main.dart
import 'package:flutter/material.dart'; import 'package:flutter_app_bloc_sample_app/src/app.dart'; void main() => runApp(App());
- app.dart
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_bloc_sample_app/src/ui/scenery_list.dart'; class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.dark(), home: Scaffold( body: SceneryList(), ), ); } }
UI Screen
- ui/scenery_list.dart
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_bloc_sample_app/src/blocs/scenery_bloc.dart'; import 'package:flutter_app_bloc_sample_app/src/models/image_model.dart'; class SceneryList extends StatelessWidget { final _bloc = SceneryBloc(); @override Widget build(BuildContext context) { _bloc.fetchAllScenery(); return Scaffold( appBar: AppBar( title: Text("景色画像一覧"), ), body: StreamBuilder( stream: _bloc.allScenery, builder: (_, snapshot) { if (snapshot.hasData) { return _buildList(snapshot); } else if (snapshot.hasError) { return Text("エラーが発生しました" + snapshot.error.toString()); } return Center( child: CircularProgressIndicator(), ); }), ); } Widget _buildList(AsyncSnapshot<List<ImageModel>> snapshot) { return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2), itemBuilder: (_, index) { ImageModel model = snapshot.data[index]; return Image.network(model.imageUrl); }, itemCount: snapshot.data.length, ); } }
BLOCの部分です。
- scenery_bloc.dart
import 'package:rxdart/rxdart.dart'; import 'package:flutter_app_bloc_sample_app/src/models/image_model.dart'; import 'package:flutter_app_bloc_sample_app/src/resources/repository.dart'; class SceneryBloc { final _repository = Repository(); final _sceneryFetcher = PublishSubject<List<ImageModel>>(); Observable<List<ImageModel>> get allScenery => _sceneryFetcher.stream; fetchAllScenery() async { List<ImageModel> imageModelList = await _repository.fetchAllProvider(); _sceneryFetcher.sink.add(imageModelList); } dispose() { _sceneryFetcher.close(); } }
次にRepository
import 'package:flutter_app_bloc_sample_app/src/models/image_model.dart'; import 'scenery_image_provider.dart'; class Repository { final provider = new SceneryImageProvider(); Future<List<ImageModel>> fetchAllProvider() => provider.fetchImageList(); }
次にNetwork Provider
import 'package:flutter_app_bloc_sample_app/src/models/image_model.dart'; import 'package:http/http.dart' show Client; import 'dart:convert'; class SceneryImageProvider { Client client = Client(); Future<List<ImageModel>> fetchImageList() async { // Json用意しておいたのでこちらを使ってみれください。 final response = await client.get( "https://firebasestorage.googleapis.com/v0/b/blog-1a47d.appspot.com/o/json%2Fdata.json?alt=media&token=e67da5e7-b8d4-4000-9dc3-394e6a5d1549"); print(response.body); if (response.statusCode == 200) { // 成功 List<dynamic> jsonArray = JsonDecoder().convert(response.body); return jsonArray.map((i) => ImageModel(i)).toList(); } else { // 失敗 throw Exception('Failed to load post'); } } }
これで完成です。
BLoCアーキテクチャを使って画像の表示するようなやつ作ってみた!! pic.twitter.com/RmCaFGe3q5
— shogo.yamada@Flutterマン (@yshogo87) 2018年12月8日
ソースコードはこちらにおきました