虚苦心観察ブログ

ブログ管理者である虚苦心が私利私欲に基づいて書いているブログです。主にガジェットのレビューだったり、画像処理のことだったりを記事にしています。

Flutterでネットワーク通信

はじめに

覚書のために書いています。

使うパッケージ

  • http

使い方

  • GET get()

  • POST post(, body: )

戻り値は Future< Response >
Responseの処理はFutureのthenメソッドにCallbackとして渡す。

余談

パッケージのインポートは

import 'package:http/http.dart' as http;

と書くが、

import 'package:http/http.dart'

と書くとネームスペースがグローバルになるみたい。
Dartの勉強がまだまだ。

FlutterのWidgetについて勉強を始める

FlutterのUI作成の特徴

画面を表示

  • すべてコードで書く
  • Widgetの構成単位が細かい
  • AndroidでいうところのLayoutに当たるものがほとんど。
  • StatelessWidgetとStateWidgetがある
    • まだ理解していない
  • Androidでいうところのlayout_gravityやgravityもWidgetとして提供されている
  • とてもシンプルなデコレーションパターンな印象
  • それ故にコード量は多い
  • しかし、それを補って余りある強力なUI表現が得られる
  • UIをコードに落とし込むときも単純な考え方で記述できるので苦労しなさそう
  • Androidでよくある「え、標準UIでこれができないの?」がほとんどない気がする
    • Androidの標準のViewは機能が豊富過ぎるわりに必要な機能を網羅できていなくて使いにくかった

画像を表示

  • ローカルで表示する場合
    • Image.asset(<画像のパス>)で表示
    • プロジェクト直下にディレクトリを作成。名前はなんでもOK
    • 表示したい画像が入ったディレクトリはpubspec.yamlに記載
    • ディレクトリだけでなくファイルも指定可能
flutter:
  assets:
    - assets/ # ディレクトリ指定
    - assets/images/image.jpg
  • ネットワーク経由で表示する場合
    • Image.network()で表示できる
  • よくある角丸はClipRRect Widgetの子に指定することで簡単に

リスト表示

ListView.builder(
  itemBuilder: (buildContext, index) => Text("current $index"),
  itemCount: 10,
)
  • 書き方はRecyclerViewととても似ている。

Flutterを始める

つまづく

UIをぽちぽちしてプロジェクトを作ってRunしただけなのに動かない・・・

やったこと

Androidアプリ開発で陥りやすいバグやあまり知られてないけど有益な実装方法をまとめる。

忘れることが多いのでちょくちょくメモしていく。

  • ダウンロードは別スレッドで行う。メインスレッドを止めてしまうためANRが発生する可能性が高い。(activity,service)
  • 画像表示は縮小した画像で行う。Android8から大きすぎる画像を表示しようとすると例外が発生する場合がある。また縮小することで大幅な高速化が可能。ただし、縮小する方法は考えること。単純な実装だとむしろ重くなってしまう場合がある。
  • recyclerviewの各ViewHolderには直接listenerを実装せずにリストの各要素にそれぞれリスナーを保持する
  • ViewHolderで画像表示やネットワーク通信をするときはViewHolderが再利用されるときに画像の解放やネットワーク通信のキャンセルをすること。
  • mvpパターンはandroidフレームワークとロジックを分離するための雛形。
  • ネットワーク通信は通信内容の処理のほかに通信失敗の処理も必須。ネットワーク通信が失敗する可能性は0ではない。
  • FcmIdRecieverServiceはDeprecated。FirebaseMessageRecieverServiceでFCMトークンの更新処理を行うこと。
  • PendingIntentに設定したTaskBackStackが反映されない場合はアプリを再インストールすると治ることがある。アプリのキャッシュやデータを削除しても治らない。(このことからわかるようにAndroidにはアプリから触れることのできないアプリにかかわる領域がある)
  • Retrofit2のマルチパートでファイルとその他をアップロードする場合はPartとPartMapだけしか使えない。PartMapはBodyにハッシュを指定する感覚で使える。
  • KotlinからRetrofit2でPartMapを使う場合、RequestBodyがワイルドカードで表現されてしまう場合がある。その時はPartMapのValueに@JvmSuppressWildcardsを付ける。参照
  • EditTextのimeOptionsにactionSearchを指定してはいけない。ソフトウェアキーボードからのエンターキーのイベントはsetOnEditorActionListenerで設定できるが、ハードウェアキーボードからのイベントは処理できずアプリが落ちてしまう。単純に検索窓として使いたいならSupport LibraryのSearchViewを使おう。継承することで見た目をカスタマイズすることもできる。どうしてもEditTextを使いたい場合はimeOptionsにactionDoneを設定すること。見た目は検索と異なってしまうが、落ちることはない。
  • RecyclerViewのOnScrollListenerに依存した初期化処理を書いてはいけない。タイミングによってイベントが発火しないときがある。なんとかして初期化処理は能動的に実行すること
  • RecyclerViewのスクロール位置復元は明示的に行う必要がある。RecyclerViewのスクロール位置を保存したいに書かれていることをonSaveInstanceStateで保存し、onRestoreInstanceStateで復元する。
  • RecyclerViewの無限スクロールにはこれがよい。無限スクロールの状態をリセットし、一旦停止した無限スクロールを再開することもできる。使い方もしっかり書かれている。
  • アスペクト比を固定するにはConstraintLayoutが使える。stackoverflow よくあるアスペクト比固定のImaveViewもImageViewを拡張せずに使うことができる。
  • デバッグ時はアプリの起動と再起動を開発者オプションの「アクティビティを保持しない」の有効無効を切り替えて確認すること。アクティビティが一時的に破棄され、復元された場合のチェックが抜けていることがよくある。
  • Maps SDK for Androidで地図をLite Modeで表示するにはViewのサイズが完全に固定されている必要がある。固定されない場合、地図が表示されない、タップしたときだけ地図が表示される、など表示崩れが発生する。サンプルコードのLayoutをそのまま使ってもうまく動作しないことがある。その時は、Viewのサイズが変わらないよう、不要な要素を排除、もしくはサイズが変わらないように変更しよう。
  • Activity間のデータやイベントのやり取りはやってはいけない。短時間での使用ではモンダイなさそうでも、長期間利用した場合にAndroidのライフサイクルと合わず、おかしな動作をしてしまう可能性が高い。
  • 逆の考えでActivityの実装を制限してデータやイベントのやり取りを可能にすることはできるかもしれないが、普通ではない実装であるが故に普通の実装をしようとしたときに後悔することになりかねない。
  • FLAG_ACTIVITY_REORDER_TO_FRONTを使って複数のActivityを切り替えて表示すると、オーバービュー画面(アプリの使用履歴が見れる画面)で最後に表示されたActivityのスクリーンショットが表示されず、どこかのタイミングで表示されたActivityの画面になってしまうことがある。Android 8のNexus 5Xで確認。改修方法はわからず。
  • RecyclerView and java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder のようなエラーが出た場合はAdapterの更新でnotifyItemRangeChangedが呼び出されているところをチェックしよう。StackOverFlowで説明されているエラーとは異なる。このエラーはsupport library のバージョンが23.1.1で発生していたもので、すでに修正済みである。ではなぜ同様のエラーが発生しているかというと、おそらくRecyclerView.AdapterのnotifyItemRangeChangedを呼び出していながら表示要素が減っていることが原因だ。notifyItemRangeChangedは表示要素が増えた場合は対応できるが、減った場合は対応できていないようだ。
  • Activity間での変更通知はLocalBroadCastManagerを使うことができる。しかし、これは本来的な使い方ではない。本来はActivityとServiceの通信で使うものである。よく検討し、ライフサイクルを考慮した実装をしなければただのバグの温床にしかならない。あるデータの変更通知を行いたいのであれば、データベースに変更日時を記録すれば、データの取得日時がそれよりも後か前かで更新すべきかどうか判断できる。もしくはデータをServiceなどで一括管理するなどが必要だろう。
  • 通知からCustomChromeTabを直接起動するとBackStackBuilderで構築したバックスタックが反映されず、CustomChromeTabが終了するとアプリも終了してしまう場合がある。Android API Level 25のバーチャルマシンで確認した。21、23、25、27と確認してのことである。解決方法はIntent.ACTIVITY_FLAG_NO_HISTORYで起動した何もしないActivityからCustomChromeTabを起動する。これでAPI LEVEL 25のバーチャルマシンでも問題なくBackstackが構築された。
  • IntentはParcelを継承しているのでそのままIntentにputExtraで保存することができる。これを利用すると何もしないACTIVITY_FLAG_NO_HISTORYで起動するActivityにIntentをExtraとして渡すことでRedirectのような動作を実現することができる。
  • Activity遷移のAnimationはNULLにしない。空のAnimationをセットすること。端末によってはNULLにしたことによってActivityの表示前に黒い画面が一瞬表示されてしまう。
  • RecyclerViewの各アイテムにもAnimationがある。ItemAnimatorを使って実現している。

sklearnのChange Logまとめ

バージョンアップでモジュールのパスなり引数の名前が変わってしまっていて、本を使って勉強をしているときに困ることが多いのでメモ。

  • パス
old path new path changed
sklearn.cross_validation sklearn.model_selection 0.18.0
sklearn.grid_search sklearn.model_selection 0.18.0
sklearn.learning_curve sklearn.model_selection 0.18.0
  • 引数 | function | old argument | new argument | changed | | :-- | :-- | :-- |

随時追加していこうかと思います。 載っていないものがあればコメントいただければ追記します。

Visual Studio 2015 で LLVM/Clang 3.6.2 をコンパイルする

LLVM/Clangはコンパイルのハードルが高いと思っていたのですが、そこまで大変ではないらしいことを知りました。

KMC Staff Blog:LLVM/Clang 3.6.2をVisualStudio 2013 Expressでビルド

上記の記事よりVisual Studioのバージョンが新しいのですが、コンパイルを試みました。 そしたらなぜかコンパイルエラーが。

Severity Code Description Project File Line Error C2664 'void llvm::BitstreamWriter::EmitRecordWithBlob<uint64_t>(unsigned int,llvm::SmallVectorImpl<uint64_t> &,llvm::StringRef)': cannot convert argument 3 from 'clang::serialization::DeclOffset *' to 'llvm::StringRef' clangSerialization  C:\Users\kyokushin\ProgramingLibraries\llvm-3.6.2.src\tools\clang\lib\Serialization\ASTWriter.cpp   2815

Visual Studioのバグでdataというテンプレート関数が別のインクルードファイルに含まれているテンプレート関数を呼び出してしまっているらしい。
エラー文からいくつかキーワードを引っ張ってググってみるとそれっぽいバグ報告を見つけた。

Bug 25650 – Cannot compile clang 3.7.0 with msvc 14 (2015)

このバグ報告によれば新しいClangでは直っているようです。なのでClang3.8.1のソースをダウンロードしてどのような変更があったのかを直接みました。 Clang3.8.1ではdataというテンプレート関数をbytesという名前に変更していることがわかり、同様の変更を加えてみました。

変更するファイルは一つ。
clang/lib/Serialization/ASTWriter.cpp

ファイル先頭にあるテンプレート関数dataを引数などはそのままで関数名のみをbytesに変更します。 同じファイル内でテンプレート関数dataを呼び出しているところをbytesに変更します。 一括置換で簡単に変更することができますが、dataというメソッド名も存在するので注意。 先頭にスペースを入れた" data("を検索文字列にすると対象となるテンプレート関数だけが置換できます。

変更後コンパイルしてみましたが、エラーなくコンパイルが終了しました。
こういうことがあると本当にVisual Studioはクソだなーって感じますね。