虎視眈々と

Flutter × Firebaseを研究するアプリエンジニア

FlutterからAPIを叩いて結果を受け取る

FlutterからAPIを叩いて結果を受け取る

FlutterからAPIを叩いてjsonを受け取るまで処理を書いていきます。

サンプルコードはこちらになりますので合わせてご確認ください。

github.com

APIクライアントを書く

一般的にAPI叩くときはこんな感じだと思います。

  1. http GET
  2. json parce
  3. オブジェクトにして返す

Flutterでは async await が使えるのでスマートかけていい感じです。

http GET

URLを叩いてる実装はこんな感じ

Future<List<ScheduleModel>> getItems() async {
    final result = await client.get("叩くAPIのURL");
    final json = (await jsonDecode(result.body)) as List<dynamic>;
    final list = json.map((j) => ScheduleModel.fromJson(j as Map<String, dynamic>)).toList();
    return list;
  }

APIを叩いてから結果を受け取りjsonDecodeしています。

ScheduleModel.fromJsonjsonをパースしています。

json parce

class ScheduleModel {

  String title;
  int time;
  String tag;
  String hour;

  ScheduleModel.fromJson(Map<String, dynamic> json)
      : title = json['title'] as String,
        time = json['time'] as int,
        tag = json['tag'] as String,
        hour = json['hour'] as String;
}

実際にパースするのはjsonの構造に適宜変えてください。

オブジェクトにして返す

これでオブジェクトにしてコールバックするので今度は呼び側を実装していきます。 今回のサンプルコードではBlocパターンを使って実装しているのでBlocのsink経由で取得します。


import 'dart:async';
import 'package:bloc_sample_app/BlocProvider.dart';
import 'package:bloc_sample_app/Schedule/ApiClient.dart';
import 'package:bloc_sample_app/Schedule/ScheduleModel.dart';

class ApiBloc implements BlocBase {

  StreamController<List<ScheduleModel>> _scheduleController = StreamController<List<ScheduleModel>>();
  StreamSink<List<ScheduleModel>> get items => _scheduleController.sink;
  Stream<List<ScheduleModel>> get outStream => _scheduleController.stream;

  ApiBloc() {

    _getItems();
  }

  @override
  void dispose() {
    _scheduleController.close();
  }

  void _getItems() async {
    final itemList = await ScheduleClient().getItems();
    _scheduleController.sink.add(itemList);
  }
}

_getItems() でメソッドでAPIを叩いてデータを取得しています。 取得したデータはsinkにaddすることでStreamが反応します。

  • View
import 'package:bloc_sample_app/BlocProvider.dart';
import 'package:bloc_sample_app/Schedule/ScheduleBloc.dart';
import 'package:bloc_sample_app/Schedule/ScheduleModel.dart';
import 'package:flutter/material.dart';

class ScheduleStateless extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<ApiBloc>(
      bloc: ApiBloc(),
      child: Schedule(),
    );
  }
}

class Schedule extends StatefulWidget {
  @override
  _ScheduleState createState() => _ScheduleState();
}

class _ScheduleState extends State<Schedule> {
  @override
  Widget build(BuildContext context) {
    final ApiBloc bloc = BlocProvider.of<ApiBloc>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text("スケジュール"),
      ),
      body: StreamBuilder<List<ScheduleModel>>(
          stream: bloc.outStream,
          builder: (context, snapshot) {
            if (snapshot == null || snapshot.data == null) {
              return Center(
                  child: CircularProgressIndicator()
              );
            }
            return ListView.builder(itemBuilder: (context, position) {
              var item = snapshot.data[position];
              return _listItems(item);
            });
          }),
    );
  }

  Widget _listItems(ScheduleModel item) {
    return Card(
      child: ListTile(
        title: Text(item.title),
        subtitle: Text(item.hour),
        trailing: Text(item.time.toString() + "時間"),
      ),
    );
  }
}

StreamBuilder クラスを使って画面にデータを取得しています。

最後に

サンプルコードは下記においたので合わせてご覧ください

github.com

Blocパターンについても記事に書いたのでこちらもどうぞ。

www.shogogeek.com

FlutterでCloud Firestoreとやりとりするチートシート

よく使うので個人的なメモとして残しておきます。 FlutterとFirebaseの連携方法については下記をご覧ください

www.shogogeek.com

データの保存

add

  • addした場合は新しいDocumentIdが生成されて新しいレコードとして保存される
Future<void> newGroup() {
    return Firestore.instance.collection("hoge").add({
      "hoge": hogehoge
    });
}

set

  • setした場合は指定のDocumentIDとしてデータを保存できる
Future<void> editGroup() {
    var db = Firestore.instance;
    return db.collection("group").document(groupID).setData({
      "hoge": hogehoge
    });
  }

参照

  • 普通にデータを取得する
  Stream<QuerySnapshot> getGroupItem(String groupId) {
    return Firestore.instance
        .collection("group")
        .document(groupId)
        .get();
  }
  • snapshotとしてデータを取得する
  Stream<QuerySnapshot> getGroupItem(String groupId) {
    return Firestore.instance
        .collection("group")
        .document(groupId)
        .snapshots();
  }
  • Document一覧を取得する
  Stream<QuerySnapshot> getGroupItem(String groupId) {
    return Firestore.instance
        .collection("group")
        .getDocuments();
  }
  • 取得順序の指定 order by

更新順序順に表示する

Stream<QuerySnapshot> getGroupItem(String groupId) {
    return Firestore.instance
        .collection("group")
        .orderBy("updated_at", descending: true)
        .snapshots();
  }
  • データを指定する where

タイトルが同じものだけ取得する

Stream<QuerySnapshot> searchGroup(String title) {
    return Firestore.instance
        .collection("group")
        .where("title", isEqualTo: title)
        .snapshots();
    }

データのupdate

Future<void> _uploadImage(String documentId,) async {
    return Firestore.instance
        .collection("group")
        .document(documentId)
        .updateData({"documentId": documentId});
  }

データの削除

Future<void> removeImage(String groupId) {
    return Firestore.instance
        .collection("group")
        .document(groupId)
        .delete();
  }

1年が13ヶ月になる 自分を操る超集中力

読んだので書評ブログとして残しておきます。

集中力を高めるには 「トレーニング」と「パワーの節約」しかない

この本では集中力とはどういうメカニズムなのかを説明した上で、集中するための様々なテクニックが紹介されています

  • 細かい作業は一気にやってしまう
  • 集中力の高い人は実は集中していない。短い集中を繰り返してるだけ
  • 脳の感じる疲れは単なる思い込みで疲れていると感じてるだけ

集中力を高める方法と回復する方法

本書では集中力を高める方法と回復する方法が書かれています。 全部は紹介しませんが、印象に残ったものだけ残しておきます

  • 姿勢に気をつける
  • 場所を選ぶ
  • 感情をコントロールする

以外に目先の簡単なことを気をつけるだけで集中力があがるんだなーと思いました。

難しいテクニックは何も紹介されていません。 今すぐにでも実行できるものばかりです。

朝のルーティーン

この本では朝のオススメのルーティーンも紹介されています。 自分も最近早起きにはまっているのですごく勉強になりました。

www.shogogeek.com

特に「朝モチベーションの上がる言葉を読む、聞く」というのは実際やってみると1日のモチベーションを1日ずっと高く保てました。

この本買ってよかったです。

Flutterでバナー広告を出す

Flutterでバナー広告を出す

Flutterからバナー広告を出せます。 これも両OS別々で実装する必要もなく、1ソースで出すことができます。

AdMobを出す

今回はAdMobを出します。 実装はとても簡単ですが、少し注意が必要なことがありましたのでその辺りも説明してきたいと思います。

プラグインを導入する

まずはいつも通りプラグインを導入します。今回導入するプラグインfirebase_admob です。

pub.dartlang.org

このプラグインはFirebaseの導入は必須なので、まだ導入していない方はこちらをご覧ください。

www.shogogeek.com

pubspec.ymlに下記を追加します

dependencies:
  flutter:
    sdk: flutter
  firebase_admob:

追加したら下記を実行

$ flutter packages get

コードを追加する

追加できたら、コードを書いていきます。

initState() メソッドに一気に書いていきます。

String appId;
BannerAd _bannerAd;

@override
  void initState() {
    super.initState();

    if (Platform.isIOS) {
      appId = "AdMob のiOSのAdID";
    } else if (Platform.isAndroid) {
      appId = "AdMob のAbdroidのAdID";
    }

    FirebaseAdMob.instance.initialize(appId: appId);
    _bannerAd = _createAd()
      ..load()
      ..show();
  }

BannerAd _createAd() {
    return BannerAd(
      adUnitId: appId,
      size: AdSize.banner,
      listener: (MobileAdEvent event) {
        print("BannerAd event $event");
      },
    );
  }

@override
  void dispose() {
    _bannerAd.dispose();
    super.dispose();
  }

これで下側に広告が追加されます。

注意

注意としては画面が切り替わるときに、(閉じる時も)必ず _bannerAd.dispose(); を必ず呼び出しましょう。 これを呼び出さないと画面の下に広告が表示され続けます。

Flutterでテストを書く

今回はFlutterでテストを書く方法について書いていきたいと思います。

テストについては公式サイトにもまとめられています。

flutter.io

Flutterではテスト用のライブラリのセットアップをしなくても利用できます。

テストを書く前に

テストを書く前に、ほぼ全てのプラットフォームに言えることですが、 Viewロジック は明確に分けるために 何かしらのアーキテクチャを導入しましょう。

FlutterではBLoC(Business Logic Component) が有名ですので、この記事ではBLoCで書かれたプロジェクトに対してテストを追加していきます。


自分が以前にBlocに関する記事を書いたのでまだ呼んでない方はこちらをご覧ください。 この記事ではここで書かれたカウントアップのソースコードを使って説明していきます。

www.shogogeek.com

カウントアップアプリを修正する

テストを書くためにカウントアップアプリを少しだけロジックを追加します。

追加する仕様は 「カウントアップしていって3の倍数のときだけFlutterと表示する」という内容です。

  • IncrementBloc.dart
import 'dart:async';

import 'package:bloc_sample_app/BlocProvider.dart';

class IncrementBloc implements BlocBase {

  int _counter;

  // handle controller
  StreamController<String> _counterController = StreamController<String>();
  StreamSink<String> get _inAdd => _counterController.sink;
  Stream<String> get outCounter => _counterController.stream;

  // handle view action
  StreamController<int> _actionController = StreamController<int>();
  StreamSink<int> get incrementCounter => _actionController.sink;

  IncrementBloc() {
    _counter = 0;
    _actionController.stream.listen(_handleLogic);
  }

  void _handleLogic(data) {
    _counter += 1;
    _inAdd.add(isMultiplesThree(_counter));
  }

  String isMultiplesThree(int counter) {

    if (counter % 3 == 0) {
      return "Flutter";
    }

    return counter.toString();
  }

  @override
  void dispose() {
    _counterController.close();
    _actionController.close();
  }
}
import 'dart:async';

import 'package:bloc_sample_app/BlocProvider.dart';
import 'package:bloc_sample_app/minimum/IncrementBloc.dart';
import 'package:flutter/material.dart';


class MinimumStateless extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<IncrementBloc>(
      bloc: IncrementBloc(),
      child: Minimum(),
    );
  }
}

class Minimum extends StatefulWidget {
  @override
  _MinimumState createState() => new _MinimumState();
}

class _MinimumState extends State<Minimum> {
  int counter = 0;

  @override
  Widget build(BuildContext context) {
    final IncrementBloc bloc = BlocProvider.of<IncrementBloc>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text("最小のBLoC"),
      ),
      body: Center(
        child: StreamBuilder<String>(
            stream: bloc.outCounter,
            initialData: counter.toString(),
            builder: (context, snapshot) {
              return Text("${snapshot.data}");
            }),
      ),
      floatingActionButton:
          FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: () {
                bloc.incrementCounter.add(counter);
              }),
    );
  }
}

f:id:superman199323:20180915101212g:plain

テストを書く

やってここでテストを書いていきましょう。 テストを書くメソッドは isMultiplesThree です。

テストコードの置き場所は test パッケージの下に置きましょう。

f:id:superman199323:20180915101829p:plain

テストの下に置いたら、一旦下記のコードを書いてテストを成功させましょう。

import 'package:flutter_test/flutter_test.dart';

void main() {

  test("3の倍数なテスト", () {
    expect(true, true);
  });
}

これが成功したらテストを書いていきます。

[f:id:superman199323:20180915102407p:plain]import 'package:bloc_sample_app/minimum/IncrementBloc.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {

  IncrementBloc bloc;
  setUp(() async {
    bloc = IncrementBloc();
  });

  test("3の倍数なテスト", () {
    expect(bloc.isMultiplesThree(33), "Flutter");
  });

  test("3の倍数でないテスト", () {
    expect(bloc.isMultiplesThree(500), "500");
  });
}

これでテストが成功したらおっけーです。

コマンドラインからテスト

ちなみにコマンドラインからテストも実行できます。 コマンドラインからテストを実行すると全てのテストが実行できるのでCIのときとかで便利ですね。

flutter test

早起きの習慣化して作業効率を高める方法

早起きを習慣化して作業効率を高める方法

自分のTwitterをフォローしていただいてる方はわかると思うんですが、最近自分早起きです。

twitter.com

自分がどうやって早起きを習慣化できるようになったのか書いていきます。

そもそもなんで早起きするのか

自分はとにかく やりたいことがおおい です。

  • Flutterで作成したGroupAlbumの開発をやりたい

www.shogogeek.com

  • ブログの投稿
  • 読書
  • 情報収集
  • 筋トレ

なのでこのための時間をどうやって捻出するかを考えたときに 時間の確保作業効率を高める の両方を高めていかないといけないと考えた時に朝の時間を確保したいと考えました。

朝の時間は誰も起きてないので邪魔されないし、頭が冴えてて作業効率が高い時間です。

上の本でもウィルパワーと呼ばれる集中力を高めるパワーみたいなものの量が一番高いのが朝だそうです。

早起きを習慣化するための施策

こういう計画を確実に遂行するには準備が大事だと自分は考えています。 そのために自分がやった施策をまとめていきます。

早く寝る

そもそも早く寝ましょう。 夜に一時間作業時間を取るなら寝たほうがいいです。

夜に一時間取っていた時間を朝に一時間取ると思って思い切って寝ましょう。

自分はだいたい毎日11時前にはベットに入っています。

作業をすぐに始められる準備をしてから寝る

夜寝る前に作業する準備をしてから寝ましょう。 自分は朝からやることをメモを取ってから寝るようにしています。

自分は明日朝からこれやると準備してから寝たほうが起きれる確率があがるのでやることは決めておきましょう

立って作業する

さっきまで準備編でしたが、これは起きてからの作業です。

立って作業しましょう。 座ると眠くなります。

でもスタンディングデスクは高すぎて買えません、、、

ですので自分はこれを机の上に置いて使っています。

これだけで立って作業できるようになります。

ちなみに立って作業すると作業効率が20%ほど上がるらしいので絶対立って作業したほうがいいです。

herb-sense.com

まとめ

いかがでしたでしょうか。 自分はこの3つの施策で早起きに成功しました。

何より朝早く起きるというのは圧倒的優越感があるので、おすすめですw

すべての仕事は10分で終わる。作業を爆速にするために

すべての仕事は10分で終わる

読み終わったので書評として残しておきます

10分単位で仕事を区切ってタスクをこなしていく

本書では仕事は10分で終わらせられて、終わらせられない仕事に対してはいろんな無駄を排除していきましょうということがかかれています。 例をあげると

  • 会議は10分
  • プレゼン資料や、プレゼンも10分
  • 議事録は3分
  • 大きな仕事は10分ごとに細分化していく
  • TODOタスクは10分単位で管理する

会議が長引くのは事前に「何をきめるのか」「決めるための選択肢を用意しておく」などの作業を決めておくことが重要とか、 他にもたくさん無駄な作業についてあげて、どんどん排除していきましょうと書かれています。

とにかくいろんな作業を捨てる

ひとつひとつの作業について無駄な作業を見直していくことがあります。

例えば

  • 完璧を求めない
  • 答えの出ないことで時間をかけない
  • 時間泥棒を見つける
  • 足を引っ張る人と仕事をしない

など結構大胆なことまでかかれています。

どんな人におすすめか

こんな人におすすめだと思います

  • 仕事を改善したい人
  • やりたいことがたくさんあるけど時間が足りない人