Bonfire Android #5 レポートを書くのが遅れたらJetpackに大リリースが来てた
はじめに
開催からだいぶ空きました(忙しくて時間がとれなかった…)が、8/19に開催されたBonfire Android #5 に参加してきました
なのでレポート的に各発表をまとめようと思います。今回のテーマは「Jetpackとサービス」ということで、Jetpackに関連する話題を中心とした発表が揃っていました。
navigationを見据えたリファクタリング~マルチモジュール化を添えて~
木内 啓輔さん (@fei_kome) ◆ ヤフー株式会社
実装・運用されている期間が長いアプリをマルチモジュール化・navigation componentsをする際に考えられていることについてお話されていました。
マルチモジュール化自体、近年トレンドになった話題で(僕はDroidKaigi 2018でマルチモジュールに関する話を初めて聴いて、そこから話題になったと感じているだけかもしれないです)、やはりそれ以前からずっと開発されていたアプリは「マルチモジュール化されることを想定していない」「モジュール分割に耐えうるような依存関係・設計ができていない」という状態にあると思っています。
それを踏まえて、実際にマルチモジュール化を実現するためUI-Presenter間の相互依存を解消するための腐敗防止層的なInterfaceを作ったりすることでnavigation componentの導入を視野に入れた切り分けを実現するといったリファクタリング過渡期の実装tipsについて紹介されていました。
マネーフォワードMEにおけるJetpackの活用事例
syarihuさん (@syarihu) ◆ 株式会社マネーフォワード
syarihuさんが以前他で発表された内容も織り交ぜながら、マネーフォワードMEがどのようにAndroidXを始めとするJetpackの導入を行っていたのか、導入から1年経って何が変わったのかについてお話されていました。 マネーフォワードMEでのJetpackの導入は
- 手入力画面のリファクタ、設計変更を含めたJetpack導入
- 月額課金機能へのPlay Billing Library導入
- LiveData、ViewModel、Lifecycleを用いてBillingViewModelを作り、どの画面でも課金機能を作りやすい状況に
- 入出金履歴画面へのBottom Navigationの導入
- 複数の遷移元が存在し複雑になってしまった更新リクエストをRxJavaのBehavingProcessorとLiveDataを用いることで簡単に扱えるように
という感じだったそうです。導入を始めてからはおおよそ1年とのことで、古い機能の刷新と並行して行う機会が多かったようで設計適用のためのリファクタではなく、多くの部分に導入を進めることができたことや、このJetpackの導入、設計変更によってテストの記述効率の向上を果たせたとのことでした。
Paging Libraryでのアイテムの更新
釘宮 愼之介さん (@kgmyshin) ◆ 合同会社DMM.com / CTO室エバンジェリストチーム
Paging Libraryを使って、チェックボックスの操作といったリストのアイテムの更新をどのようにUIまで反映させるかについてお話されていました。 基本的な実装手順からよく躓くポイントとして
- アイテムがアップデートされない
- ItemRepositoryに新しいデータを保存する
- DataSourceをinvalidateして再取得を走らせる
- 更新はしたもののスクロール位置が急に最初に戻る
- initialzeKeyがPageKeyedDataSourceを使ってる限りnullになるから
- 対策としてRoomを使う
- DatabaseとDaoを作ることでDataSource周りをよしなに作ってくれる
- マイグレーションが大変、このためだけにDBを持ちたくない場合はInMemoryでも使える
- Roomを使わなくてもできる
- BoundaryCallbackを扱うItemDataProviderを自前で実装することで実現できる
- Repositoryがページ単位を、DataSourceがItem単位を扱うと考えて実装する
それぞれのやり方についてサンプルも公開されているので、気になる方は確認してみましょう。
Roomとコルーチンと私
荒木 佑一さん (@yuichi_araki) ◆ Google
Room 2.2.0-alpha02でのアップデートとして様々な機能が追加されましたが、その中でもCoroutines Flowを主眼において解説されていました。
Room自体、2.1.0でsuspend functionに対応して、coroutineで書くとメインスレッドでinsert等のメソッドを実行してもsuspendしてバックグラウンドに行ってくれる、というような解釈をしてくれるようになっており、更に Transaction アノテーションを付与することでcoroutinesが取り消されたり、エラーになったときに処理全体を取り消したりできる機能が追加されています。
Room 2.2.0では、これらに加えてCoroutines Flowに対応しており、Coroutines Flowの特徴である
- コールドストリーム(cf. Channel:ホットストリーム)
- アクセスされるまで処理が実行されない遅延評価
- コンテキスト保持
- Dispatcherを指定できる
- 例外透過
- .catchで例外を補足できる
といった恩恵を受けることができ、DB操作を監視した処理ができるようになるなどしています。
また、RoomのDaoの内部実装でどのようにCoroutinesを実行しているかという話や、Roomが非同期実行の際にトランザクション、スレッドを適切にハンドリングしていることについても言及されていました。
jetpackのNavigationと関連UIコンポーネント
樫村 実紅さん (@k_miku) ◆ ヤフー株式会社
www.slideshare.net
開発されているアプリにNavigationを導入された際のことについてお話されていました、ヤフーニュースアプリ、一つの大きい改修を行う際には一つ新しい技術にチャレンジすることを掲げているそうですね。
各画面の遷移をなめらかにするために1-Activity / n-Fragment構成を実現すること、Fragmentの遷移管理の負担を下げること、トレンドへの追従を目的としてNavigation導入を行ったということで、実際に導入する中で躓いたポイントとして
- ActionBarと連動をさせようとすると仕様に合わない
- Resource XMLに定義した文字列のタイトル反映はできるが画像やEditText、動的な文字列といったものは出せない
- 結果としてActionBarと連動させることは諦め、各画面でActionBarをそれぞれ操作することにした
- 画面遷移時のアニメーションのカスタマイズ
- NavigationUI#setupWithNavControllerを使う際、デフォルトで指定されているアニメーションしか使えない
- OnNavigationItemSelectedListenerを自前で作り、その中でNavOptionsをbuildすることでカスタムのアニメーションを設定した
- 画面遷移時に遷移以外の操作を行いたい
- 遷移したというユーザ行動等のログを取る必要がある
- 同様に、OnNavigationItemSelectedListenerを自前で作り、その中でItemのIDをみてログを送信した
という手段とをって解決されていました。
あまりにも遅筆過ぎた結果Jetpackが大リリースしてた
完全に怠慢の限りなのですが、イベント後しばらくたった9/5のタイミングでJetpackに大きなリリースがやってきて、いろんなコンポーネントがstableになったりしました。Room 2.2.0もrc1になったりしています。
先日あったca.apk #8で発表された資料を引用するのですが、Activityも1.0.0でFragmentのバックハンドリングが onBackPressedDispatcher で行えるようになっていたり、Activity(1.0.0) / Fragment(1.1.0)でLayout ID Constructorが追加され、layoutのリソースIDを引数に渡すことでsetContentView / onCreateViewを省略できるようになったり、いろんなトピックスが起きています。
Androidに限らず、この手のアップデートがすごい勢いで行われるのでBonfireを始めとした勉強会で新しい知識を気軽に知ることができるのはすごい素晴らしいと思います。インプットした知識を現場に還元し、また新たなアウトプットを生み出せるといいなと思いました。
最後に
Bonfire Androidを主催してくださったヤフーさん、本当にありがとうございました。レポートを書くのが非常に遅くなってしまい大変申し訳ありませんでした… :bow:
Bonfire Android #4 に参加してきた #yjbonfire
久々に勉強会に行ってきたブログを書きます。
Yahoo! Japanさん主催のBonfire Android #4にブログ枠として参加してきました。
Bonfire Androidでは毎回テーマを決めてYahoo! Japanさん内外から登壇されるのですが、今回は「UI」がテーマと言うことで、5人のデザイナー・エンジニアの方がチームでのデザイン手法、UI開発といったトピックを発表されていました。本記事では、各発表を振り返っていこうと思います。
Yahoo!乗換案内アプリでのデザイナーの役割について(山浦優樹さん)
エンジニア・デザイナーそれぞれ二人づつで開発されているというYahoo!乗換案内アプリでのデザイナーの立ち回りについて話されていました。初期はデザイン工数等の関係で以前はAndroid/iOSで共通のデザインを使っていた状況からMaterial Designを始めとしたAndroidデフォルトなデザインへ寄せていく中で、デザイナーがMaterial Design、Theme、Design Support LibraryといったUIに関わるAndroidの技術に対しての知識を持っていったことや、実際にLayout XMLをデザイナーが編集する、というようにデザイナーができることを大きくしていく中で
- デザイナーはUIの磨き込みに集中できるように
- エンジニアは実装に集中できるように
という2つの環境を実現するためのデザインフローについてのお話をされていました。
一方で、実際にデザイナーがAndroid Studio上でLayout XML/Drawable XMLといったResourcesを作るという役割の拡大について、自分で触ることでエンジニア以外には得にくかった「アプリデザインではプラットフォームごとにどのパーツが使えるかを知れる」というメリットはあるもののそこに踏み込むことの難しさについても触れられていて、HTML/CSSでのWebDev領域のようなハブとなれるプレイヤーを立てることでうまく回るのでは、と述べられていました。
”Material Designの変化”の中でアプリエンジニアができること(中村恵太さん)
2014年6月に公開されたMaterial Design Guidelineにおよそ4ヶ月で準拠したラクマのフリル時代から今の新ラクマまでのMaterial Designまでの変遷に触れて、初期のMaterial Designのメリットとして
- ユーザエンゲージメントにとどまらないメリットがある
- 開発効率
- エンジニアのデザインへの意識が上がる
- デザイナーとデザインについて議論する際の共通言語になれるかも
という点があるものの
といったデメリットが有ると述べられていました。その後Material DesignにLaunch ScreenやBottom Navigationといった新しいコンポーネントや2018年5月に公開されたMaterial Design Guideline 2.0によってブランド表現が柔軟になったこと、変化を継続していくデザインシステムになったことを説明し、その中でアプリエンジニアは何ができるのかということで
- 変化に柔軟(であろう)というエンジニアの強みをUI領域にも持ち込む
- 個人的にはアンテナを張っている、新しい情報へのリーチが早い、ということかなと解釈しています
- Material Designのキャッチアップをただの情報共有ではなく課題解決目線として提案していく
- 何が表現できて、どうプロダクトに取り込めて、結果何が解決できるのかという具体的な提案
というアクションの提案をされていました。この提案のためにSketchプラグインであるMaterial Theming Editorをエンジニアが提案のためのツールとして用いることでデザイナーの改善イメージのサポートに役立てようと動いていることが興味深かったです。
自由度の高いアプリ内UIを実現するためのKARTE SDKの仕組み(中間亮彬)
トラッキングや分析、アプリ内メッセージやプッシュ通知を行うことができるKARTEのアプリSDKについて、特にアプリ内メッセージについての実装面でのお話をされていました。アプリ内メッセージへのアプローチとしてフォーマットに従って配信するネイティブ実装とHTML/CSSを管理画面上で記述するWebView実装があること、カスタマイズ性を重視してWebViewでの実装を選択したことについてまず触れ、実際にKARTE SDKの内部構成やその中でのデータフローといった技術的な要素によってWeb・アプリ双方で同じUIとしてアプリ内メッセージを提供することを実現することについてお話されていました。
UI改善に繋がるエンジニアの立ち回り(瀬戸優之さん)
デザイナーとやり取りができる、工数の巻き戻しができる人を対象として、必要な知識がデザイナーとエンジニアで重なる部分があるUI改善のためにエンジニアはどう立ち回るべきか、というお話をされていました。
まず普段からエンジニアができることとして、デザイナーがアンテナを張っていても情報を得にくい部分である、
- 環境について
- ProgressDialogが非推奨になっている、というような実装レベルでのUIパーツの使用可否
- Material Design Components(MDC)についての情報
- そもそもAndroidXが必要
- ではプロダクトがいつからAndroidXに対応して、いつからMDCを使えるようになるのか
- 実装について
- 工数見積
- Material Design Guideline 2.0で定義されたExtended FABがボタンで作れること
- ダイアログがダイアログを出すのような二重表示ができないこと
というような情報を共有することで早い段階での気付きにつなげていくという点に触れ、そのためにコミュニケーションポイントを増やす必要があり、頻度が高いコミュニケーションほどコストが掛かるものの、Material Design Guideline輪読会のような定期的な会を行うことでMaterial Designの知見や共通認識・AnimationやComponentといった環境や実装の話といったコミュニケーションを実現するという提案をされていました。また、エンジニアが気にするべきデザインのチェックポイントとして
- 画面回転や横レイアウト
- 直しにくい、工数的に厳しい場合は画面回転・横レイアウトを許可しないという手もある
- Empty Status
- オフライン時挙動
- キャッシュを出すのかそもそも動作を止めるのか
- マルチウィンドウ、縦長ディスプレイ
- そもそも非対応にするのか、UIの要素を伸ばすならどこか
- コードレベルでのチェックポイント
- エラー通知
- try-catch / onErrorのフィードバックが存在しているか
- 仕様が複雑化していないか
- 異常に複雑な実装は仕様からすでに複雑になっているかもしれない
- エラー通知
- ユーザ目線でのチェックポイント
- 操作の手数
- エンジニアが操作に疲れるならユーザも疲れる
- 大体1画面3操作を意識する
- RAILモデルを利用した動作速度ベンチマーク
- 操作から100ms反応が無いとユーザは困惑する
- 1000msかかるとユーザの離脱率が上がる
- 操作の手数
という点を挙げられていました。日頃の仕事でも考えているものもあれば、全然気にしていなかった事もあって、すぐ効果が出るわけではないものの、これから意識して実践することによって少しでも改善に貢献していきたいと思いました。
エクストリーム・プログラミング開発におけるUIテスト〜ライブコーディングを添えて(飯島彩輝さん、松田悠吾さん)
LEAN XPを導入しているヤフオクチームでの実際の開発事例をライブコーディングを交えて説明されていました。
何を作るか?を絞るLEANとどうやって作るか?を絞るXPを組み合わせたLEAN XPにまず触れ、その中の要素としてペアプログラミング、テスト駆動開発、ユーザーストーリー(とストーリーポイント)を始めとしたものがあること、実際にヤフオクチームで実践しているPivotal Tracker上でのユーザーストーリー管理からのじゃんけん見積もりによるストーリーポイントを決定することによるチーム内での認識齟齬の解消、片方がテストを先に組み、片方が実装を行うペアプログラミングによるテスト駆動開発をライブコーディングしていく中で
- 同じ画面を見ながら開発で早い段階でミスに気づくことができる
- どういう実装をチームの人がするのかをリアルタイムで見れることでレビューコストを減少できる
- テストコードが仕様書と化すので、開発へ大きく時間を割くことができる
- ユーザーストーリーの実装ごとにリリースを行うことで効果を都度確認することができる
という利点を挙げられていました。また、実際の導入効果として、
- シナリオテストの失敗率の大幅な減少
- 手戻りが減った
といった点をお話されていました。
後記
登壇者の方々、主催、運営のYahoo! Japanさん、本当にありがとうございました!
ちゃんとレポートをしたのは久しぶりなのですごく疲れました。
エンジニア懇親会というと、寿司!ピザ!みたいなイメージなのですが、今回の懇親会はすごくおしゃれな感じでした。 きっきパイセン( @dnc_pop30 )に聞いてみたところ、ツイートに上げた写真を使っていいと言われたので飯テロ写真を置いておきます(ありがとうございます)。
😇😇😇 #yjbonfire pic.twitter.com/nKRRXNvK9M
— きっき(「・ω・)「 (@dnc_pop30) March 1, 2019
DroidKaigi 2019に参加していました(スタッフ)
感想録です。DroidKaigiも終わって2週間位たったのでエモい気持ちも落ち着いてきたかな?という感じなので気持ち的なものを備忘しておこうかなという…。
今年もDroidKaigiが行われました。 DroidKaigi 2016からなんやかんやで就活といい感じに予定を合わせて参加させてもらったり、上京したので気兼ねなく参加できるようになっていったのですが、今回はスタッフになっていました。登壇者になりたいなーって言っていたらスタッフになっていました。
スタッフになるまで
2018に参加する前後(だった気がする)に @pside さんとランチに行ってそのタイミングで「スタッフ興味ある?」「それなりにはあります」みたいな会話をしていたら、忘れた頃にDMでスタッフにリクルーティングされました。「一緒に血反吐を吐こうな」という言葉で契約(?)を結んだのがとても印象的でした。
何してたの
当日に向けては大体Codelabs班・写真班として活動していました。
Codelabs
Day 1/2ともにRoom5(ロビー入って左に進むとある小さめの部屋)でやっていたCodelabsのスタッフを主たる業務として動いていました。いわゆる「メンターさん」的な感じにしようかなーと意識はしていて、大体次のムーブをできればいいなと思いながらこなしていました。
- 部屋の隅に固まらない、くるくる歩く
- 手の上がった人がいればすぐ行く
- 手の上がっていない人にも軽く話しかけたり、困ってそうであれば一緒にコード見てみたり
- 本当は今何をしているか、どうすれば解決できるかをうまいこと理解レベルの溝を埋めながら話ができると良かった
- 気にはしていたものの多分できてない…
「初心者からその先へ」みたいな感じをキーワードに当初はしていて、Google Codelabs で選べるものとは別に以下のような題材を選んでいました。
Googleが2018/10に公開したAndroidの基礎コースですね。ActivityやUI周りといった基礎的なコンポーネントや非同期処理、ユーザデータの保存と言ったトピックをConstraintLayoutやRoomなどの新しいポイントを使って学んでいく、という感じのCodelabs集という感じです。
App Improvement Challengeという、DroidKaigiのためにCodelabs班で開発したオリジナルのCodelabsです。イメージとしては「Androidを始めた人が現場に入って、案件とどう向き合うべきなんだろう…?」みたいなものを題材に、既存コードにどう影響を加えずに手を入れていくか、また余裕があるときに Jetpack Architecture Guide を基準としてどうリファクタしてくべきなんだろう…?みたいな思いを込めていたはずだったのですが、題材開発がやたらと盛り上がった結果何かよくわからないけどすごいものが出来上がりました(ちょっと難易度がハードコアすぎた感があるので反省点かなと思ったりしています…)。このタイミングに「修正すべき点があるコード」というapproveを行うために LBTM(Looks Bad To Me)という謎の褒め言葉が生まれました。メイン開発をしていた @ymnd さん、 tomoya0x00 さん、本当にお疲れ様でした!
このCodelabsにずっと入り浸って参加してくださった方々がいらっしゃったり、参加してくださった方々からリファクタの結果をPRとして送っていただいていたりしていて、なんか語彙力がない感じでいうと「すごい、うれしい」としか言いようのない感じでした。本当にありがとうございました!
ちなみにこのリポジトリの中で一番好きな部分は計測通信を行っている(という体の) IngestManager クラスとやたらめったらテクニカルなAsyncTaskが跋扈する記事一覧を取得する loadTopStories メソッドでした。
カメラ班
DroidKaigi 2019 の写真を公開しました 🎉 https://t.co/0WkOv9ND4V
— DroidKaigi (@DroidKaigi) February 15, 2019
上のアルバムに載せるような写真を撮影をするなどしておりました。腕章付けてカメラ2台を肩から下げて、基本Codelabs部屋を常駐しながらワイワイ撮影していました。
#DroidKaigi 終了。写真班とCodelabs班の兼任でした。α7IIIとSEL70200GMも借りてこれまでで一番重い装備で戦えました pic.twitter.com/RmiWCEw1Rb
— どくぴー (@e10dokup) February 8, 2019
装備としては
自前:Sony α7II + SEL24105G + Godox TT350s(ほぼストロボ炊いていない)
レンタル:Sony α7III + SEL70200GM
という感じで二日間過ごしていました。新古品からα7IIを買っただけだったのでα7IIIにあまり食指が動いていなかったんですがα7IIIってすげぇんだなと思いました。AF-Cで瞳AF追尾できるってすごい。
後日、社内で撮影の用事があったので自前装備を使ったんですが足りねぇ…!!という気持ちになったので近い内にSEL70200G(GMじゃないよ)を買うことになりそうです。さっき発表されていたタムロンの35-150mmとかすごくいいなぁと思っているのですがEマウント用出ないですかね…?
Fireside Chat
Codelabs班の一環なのですが、パーティ前にホールでやっていたFireside Chatの話題の用意やスライド作成といった下準備をやっていました。当日は撮影担当をしていたので司会は @satsukies と @shanonim さんにお願いしました。@takahirom さんを始めとした公式アプリメンバーの方々にも急に参加をお願いしてしまったんですが最終的には沢山の方々に来ていただいて、盛況だったと思います(盛況すぎてほぼ最前にいないと話がよく聞こえてこないようなレベルだったので申し訳ないです…)。本当にいい感じに進めていただいてありがとうございました…!
Visualizer
同時期にスタッフに参加した @satsukies が @pside さんからVisualizerの開発を引き継いだので、二人で2019年対応をしていました。これまでのVisualizerについては次の記事を見ると良さそうです。
OP前に流れていたアレです。リポジトリも今の時点で公開されているものをそのまま引き継いで二人で開発していました。
今年の Visualizer を公開しました! https://t.co/6ybhwcujBG こちらのリンクよりご覧いただけます。 https://t.co/9CFmji7rEn #DroidKaigi
— DroidKaigi (@DroidKaigi) February 11, 2019
やったこととしては大体以下の感じでした
- 画面サイズが去年の4:3から16:9に変化したのでそれに合わせて画面を有効に使えるように変更してみた
- 会場では左右が若干見切れていたみたいでくるくる回っていた部分がよくわからない感じになっていたぞ
- 色とかロゴの2019化
- スライドの告知文言の追加・変更
- VisualizerのVisualizer(?)部分が動かなくなっていたので動かせるように修正
- ChromeのAutoplay Policyのせいでユーザ起因でないとAudioContextが取れなくなってたので、マイクが使えなくなっていた
- なのでもうSTARTボタンを押すと始まるようにした(安直)
satsukiesもぼくもJSよくわかんないReact.jsよくわかんない言いながらなんとかそれっぽくなったので一旦満足です。ただ、コードベースには昨年比でほとんど手を加えていないのと、Typescript化したいとかいうissueが立っていたりするので勉強して来年頑張る…頑張る…?という気持ちです。
ほか
Codelabsの参加者アンケートでお配りしてめっちゃデカイ缶バッジ、自称ドデ缶バッジを作っていました。直径は10cmです。
#DroidKaigi Codelabsでは「Android App Improvement Challenge」を実施しています。参加してアンケートに答えると今回のCodelabs限定缶バッジ(とてもおおきい)をプレゼント😎
— shanon (@shanonim) February 8, 2019
入退場自由ですのでお気軽にお越しください! pic.twitter.com/hYB7Qi67jY
あとは開催後に荷物の片付けをしたりしていました、帰りは @satsukies と @ymnd さんとsteamだったりゲームボーイカラーだったり、ゲームの話をしながらゆるゆる帰っていました。
終わってみて
なんやかんや12月付近からすっごい慌ただしくなったなという感じでした(忙しくてもなんやかんやOK出してくれた会社の人には感謝です…)。
とは言うものコアな部分にはあまりいなかった(ここで言うコアは会場周りとか司会周りとかの人だと思っています)ので、本当に忙しい人はもっと忙しかったんだよなぁ…と。
来年もなにか力になれるといいなと思ったし、来年こそ忙しくなってもいいから登壇をしたいという気持ちになりました。来年は時期が来たらCfPを頑張って書いていこうな。
かしこ
お酒を飲みながらWorkManagerのCodelabsをしてお勉強をした
なにこれ
本記事は 飲酒プログラミング Advent Calendar 2018 - Adventar の22日目の記事になります。
え?投稿日がそれより遅いって?知らないなぁ…。初日がまだ未投稿らしいのでそれより早ければセーフという謎理論で挑みたいと思います。
どうやらdescriptionを見ている限り、お酒を飲みながら何かしらのプログラミングに関するアクションを起こせばセーフということで、前々から理解しないとなぁと思っていたWorkManager周りのお勉強をCodelabsベースで概観だけでも把握すべくお酒を飲んでダラダラと実行しました。
書き始める前に
やっぱりお酒を飲むということで今回の飲酒の証拠を残しておきます。
ほいじゃあ飲酒プログラミングやっていきましょう pic.twitter.com/Ho5lNGBzw7
— どくぴー (@e10dokup) 2018年12月22日
ヤッホーブルーイングのTOKYO BLACKです。なんでまともに正面から撮らないんだこいつは。
ちなみにこれはCodelabs実践中の飲酒で、記事執筆のためにスーパードライと余っていた久保田 千寿も摂取するなどしております。昨日は飲んでコード書いていたら終了しました。
WorkManagerとは?
Android Jetpackのひとつであり、アップロード処理やフォアグラウンドで実行してしまうとUIを長時間ロックしてしまいそうな適宜実行されたり実行保証が必要なバックグラウンドタスクを行うArchitecture Componentです。
これまでAndroidのバックグラウンド処理を扱う物というとForeground Serviceでベッタリ書いてみたりJobScheduler, FirebaseJobDispatcher, AlarmManagerといったものをAPIレベルに応じて使い分けたりする必要があったのですが、WorkManager内でこれらを適切に使い分けてくれるようになります。
ちなみに現在はstable、というわけではなく、12/19にbeta01がリリースされました。思ったよりタイムリー。
Codelabsをやっていく
Background Work with WorkManager
Google I/O 2018のタイミングでWorkManagerが登場したのですが、それに合わせてCodelabsも公開されているので、これとにらめっこしながら概観を追いかけていくことができます。
ちなみに12/23時点でCodelabs内で指定されているバージョンが1.0.0-bata01になっているのですが、Codelabs中で扱っているコードがBreaking changeの発生した1.0.0-alpha13より前の物となっており、いわゆるコピペコードでは動作しないものになっているので注意しましょう。Codelabsで用意されているリポジトリはちゃんと1.0.0-beta01に追従されているのでそちらを参考にする場合は特に不都合ないと思います。
参考 -> Architecture Components Release Notes | Android Developers
ちなみにCodelabsではバックグラウンドで画像にブラーをかけるアプリが題材になっています。実際にブラーをはける処理はすでに実装されていて、WorkManagerにつないだりする部分だけを自分で加えていく形なので本質を捉えやすいかと。
とりあえずWorkManagerで出てくる登場人物を知る
Worker
WorkManagerによってバックグラウンドで処理されるロジックを扱うクラス。
Worker
をextendsし、 doWork()
中に実行されるロジックを記す。
※ doWork()
の返り値となっている Worker.Result
の返り値が1.0.0-alpha13で変更されており、Codelabs中に記されている Worker.Result.SUCCES
という定数指定から Worker.Result.success()
というような形になりました。後述のoutputDataもここに引数に入れることでよくなります。
WorkRequest
Workerを実行するリクエスト。 作ったWorkerを渡してRequestを作成し、WorkManagerに渡すクラス。このWorkRequestが実行キューに積まれる感じ。 OneTimeWorkRequest(一度だけ実行)/PeriodicWorkRequest(定期的な実行)があり、Constraintsを使って実行条件を指定したりできる。
WorkManager
依頼されたWorkRequestをスケジュールして実行するクラス。WorkRequestで指定したConstraintsを満たしつつ、負荷を分散しながらスケジュールしてキューに入っているWorkRequestを実行する。
簡単な扱い方
extends Worker
なクラスを用意するdoWork()
メソッドをオーバーライドして必要なロジックをそこに実装する- 処理の成功、失敗を
Worker.Result.success() / Worker.Result.failure()
でreturnする
- WorkRequestに作ったWorkerを入れて、Requestを作成する
- 特に指定がなく、一度だけ実行するだけなら
OneTimeWorkRequest.from(HogeWorker.class)
でOK
- 特に指定がなく、一度だけ実行するだけなら
- WorkManagerにenqueueする
- 特になんてことはなく、作ったWorkRequestを
workManager.enqueue(request)
するだけ
- 特になんてことはなく、作ったWorkRequestを
Workerに値を渡す
ファイルを取得して実行するためにURI Stringとかが必要な場合はDataクラスがあるのでこれを使います。扱い方としてはIntentのExtraみたいな感じで、Data.Builder().putString("KEY", "VALUE").build()
のようにし、WorkRequestを from
で一発で作らずにbuilderを使って作ります。
OneTimeWorkRequest.Builder(HogeWorker.class) .setInputData(data) .build()
実際に受け取った値をWorker中で取り出すためには、Worker側で getInputData().getString("KEY")
で
複数の処理を連結して実行する。
CodelabsではChain your worksと書いてある節です。複数のWorkerを逐次実行することが可能で、題材となっているアプリでは
ディレクトリのクリーンアップ -> ブラー処理(強度に応じて複数回) -> ファイル保存
という一連の流れをchainしています。実装としてはWorkContinuationクラスを使います。 WorkManager#beginWith
で起点となるWorkRequestを渡して、 WorkContinuation#then
にそれ以降に続くWorkRequestを渡していき、最終的にWorkContinuation自体をenqueueすることで実行されます。
// AWorker -> BWorker -> CWorkerの順に実行されていくWorkContinuationの例 val continuation = workManager.beginWith(OneTimeWorkRequest.from(AWorker::class.java)) continuation.then(OneTimeWorkRequest.from(BWorker::class.java)) continuation.then(OneTimeWorkRequest.from(CWorker::class.java)) continuation.enqueue()
また、このままだと重複実行を許すので beginWith
を beginUniqueWork
にすることで重複実行を防ぐことができます
var continuation = workManager.beginUniqueWork( "unique_work_id", ExistingWorkPolicy.REPLACE, OneTimeWorkRequest.from(AWorker::class.java) )
Constraintsを使って実行を制限する
WorkRequestのBuilderがsetConstraints()
というメソッドを持っており、この中に以下のようにビルドしたConstraintsを渡すことでWorkerの実行を状態に応じて制限することができます。
/// 端末充電中でのみ実行するConstraints val constraints = new Constraints.Builder() .setRequiresCharging(true) .build();
この他にも、NetworkTypeに応じて実行を制限できたり(METERED/UNMETEREDがあるのでおそらく従量課金かそうでないかを判断している…らしい?)、バッテリ残量、ストレージ残量に応じて実行を制限できたりします。
まとめ
寄った勢いなのでがっさり + この話は色んな人が先に触れている気がするのでなんとなくやってみたレポートでした。これ以外にもWorkerでの実行状態の取得(WorkStatus)ができたり、これまでAPI分岐を考えたり自前で実行可否の判定処理を実装していたりした部分が割とWorkManagerが吸い取ってくれそうでいい話感があります。
なんでこれを扱おうと思ったのかというと、以前勉強会で発表した資料がForeground Serviceをガッツリ使っていて、WorkManagerとか使ったらいいのに…というアドバイスを頂きまして、そのノリで「じゃあお酒飲みながら勉強してみますかー」という感じでした。
実際多分ググったほうが詳しい解説をしていらっしゃる方がいると思うのでほぼ備忘録です。ここまでお付き合いくださりありがとうございました。
中古ガジェット沼について
本記事は 沼 Advent Calendar 2018 - Adventar 8日目の記事となっております。
Advent Calendarは毎年情報量過多なので今年はあまり知見にならない記事を書きたい @e10dokup です。
というわけで趣味を垂れ流して完全に良さそうな沼 Advent Calendar行ってみましょう。
中古ガジェット
文字通り、中古のガジェットですね。
定義は様々なのであれですが、スマホからパソコン、オーディオ機器、カメラなんかが中古でありますね。
結構掘り出し物だったり、特集な品物がある上に新品とは違って常に同じものがあるわけでもないので、金ではなく時間が溶ける特集な沼だと思っています。
そんな中古ガジェット沼の生態を見ていきましょう。
中古ガジェット沼の行動傾向
中古ガジェット沼の朝は早…いわけでは別にないですね。はい。
ただし毎日(というか週末前から?)欠かさずチェックするものがあります。
と
の2つですね。ただしこれは秋葉原が行動圏内に入っていない限りはあまり効果がないので大阪日本橋が行動圏内な人はその限りじゃなかったりします。それでもない人は…どうなんだろう。
これらのサイトは秋葉原の特価情報を扱っており、休日の前日くらいから各ショップがどんな商品を特価で売り出すだの、そんな情報が流れてくるんですよね。
それらを確認して、めぼしいものに目をつけたりつけなかったりやっぱいいやってなったりするわけです。
そして特にめぼしいものがあろうがなかろうがその中古ショップ目指してほぼ毎週秋葉原や日本橋に向かいというわけですね。
なんで毎週なんだ、みたいな話があるんですが特価情報に上がっていない商品でも時々良さげなものが仕入れられたりしたりしていて、地味に手が出そうになったりします。
そういう取りこぼしを避けるために物理的にポーリングしに行く、という時間の無駄(重要)を強いられる沼です。
中古ガジェット沼の溶かし方
時間
前述のように物理ポーリングをするわけですが、打率は大概激低で基本的に何もせずに帰る、 みたいな結果を起こすのがザラなので毎週時間が無為に溶けます。
akiba-pc.watchなりで見た商品が気になって見に行くも「うーん、これじゃあないな?」みたいな感想になってしまってスルーすることがやたらあります。つらい。
そのため、せめてもの対策として秋葉原や日本橋を巡回する最適ルートを構築しだします。めぼしいものがありそうな店をいかに効率よく周るか、みたいな。
なのでやたらと路地裏に詳しくなったりするのが副次的効果だったりそうじゃなかったりしますね。
金
もし、何かの間違いか運命のめぐり合わせか欲しいものに出会ってしまった場合、あなたはそれなりの決断に迫られるでしょう。
あなたが欲しいとチラとでも思ってしまったものは誰かも同じことを考えているものかもしれません。中古商品は数に限りがある上、同じコンディションの物は存在しないのです。
そこに「あとで買おう」などという選択肢は存在しておらず「今買うか?」「無視するか?」の2つしか存在していないのです。
後は…、新品で買えばあれくらいだから…と新品に対する金銭的ハードルが少し上がることでしょう。
安く済ませることは大事ではあるのですが、正直新品にまさるものはないので溶かしたくない感覚ですね。
あと、akiba-pc.watch等のサイトでよく輸入端末(Xiaomiとかとか)が仕入れられたりしていて、確認すると「日本での使用可否は不明」などと記述されているのですがつまりそういうことです。 技適…
念のためですが、 この記事は決して技適承認のない商品を購入しそれをLTE環境等の電波を発する状況で使用することをおすすめするものでは一切ありません。
私自身も購入するものは技適承認が通っているものを買うようにしています。ですが日本でもXiaomi端末使いたいので(Mi 8ほしい…)なんとかなってほしいなぁと思ってます。頼む総務省。
私の今年の沼履歴
2018年。平成最後の沼イヤーに買ったものをプレイバックしていきましょう。
Surface Pro 2
秋葉原のイオシスで2月くらいに購入。47800円で箱全部入りのi5-4300U/8GB RAM/256GB SSDのモデルでした。
ちょっと割高じゃなぁい?みたいな雰囲気だったのですがこのSurface Pro 2、Office 2013のライセンスが残っているので実質15000円分くらいアドっぽいです。
ちょっと面倒な書類とかだとわざわざExcel引っ張り出したりしないといけないので、やはりOfficeが使える端末(Windowsが使えるならなおさら)はあるといいんですよね。
あとSurface Pro 2はタッチペンがWacom製(3以降はN-Trig…)でペンの書き味も良かったなぁと。
ちなみに今はもう手元には存在しておらず、知り合いに同額で売り払いました。いい端末だったよSurface Pro 2…。
dtab Compact d-01J
6月くらいに一斉入荷していたHuawei製タブレットですね。未使用で14800円と謎にお安かったのでかなり取り上げられて話題になって、すぐ売り切れていました。
旧dtabを比較するとだいぶスペックが良くなっていて、AndroidのOSバージョンも7.0まではサポートしているのでそれなりどころか割と使えるいいタブレットです。
実はネットワーク制限が△(いわゆる赤ロムになる可能性のある端末)なんですが最近こういうのは赤ロム永久保証がついていて、モバイルネットワークが使えなくなったら全額返金返品ができるのも手軽に買えた理由ですかね。
そもそもタブレットなのでSIM入れて運用する気がなかったっていうのもある気がしますが…。WQHDなのもあっていい読書端末になってしまっています。
Sony WH-1000XM2
言わずとしれたソニーのワイヤレスノイズキャンセリングヘッドホン。今はUSB-C給電になって音質もNC性能も良くなったM3が発売されていますね。
実際M3のほうがいいかなーって思ったりもしたのですが、未使用の品が21800円で売られていたので購入しました。シボ加工がされていて微妙に高級感がある。
仕事場とかで使ったり、新幹線でボーッとするときに使ったりしているのですが、明らかに静かになってすごいという感じです。ソニーのNCをオンにしたときのスゥ…ってノイズが消えていく演出がすごいニクい。
BUFFALO WSR-2533DHP2
BAFFALOのいい家庭用ルータですね。こちらは日本橋のお店でアウトレット品として新品(?)を5000円で買いました。
箱もいつものBAFFALOの箱ではなく無地ダンボールだし、保証なんかあるわけ無いだろ!みたいな感じの超ストイックな売られ方をしていたのですが、まぁ5000円でこれ買えるなら…みたいな感じでスッと購入してしまいました。
実家のNEC Atermがオンボロになってしまったのでこれにリプレースしたところ、とりあえず3ヶ月くらい経って元気に動いているし回線速度もベストエフォートに近い値が安定して出るようになったのでとりあえずは健康そうです。
自宅にも一台買えばよかった…
Sony α7II +SEL24105G
こちらは渋谷のじゃんぱらでたまたまシリアルだけ抜き取られた新古品があったので衝動買い。当時15万円弱だったα7IIレンズキットが10万で買えました。
んで、フルサイズEマウントだったらほしいなーと思っていたSEL24105G(24-105mm F4通し)も人気がありすぎて品薄で手に入らないしまってますか…みたいな感じだったのですがマップカメラにある日突然美品が流れてきたのでこちらも衝動買い。
こっちは定価だったんですが、無事にいい感じに整ってしまったので人やイベントを撮りたいときはこれにレンズをレンタルしたりして運用したり、モータースポーツを撮りたいときは以前持っていたPENTAX K-S2を持っていったりしています。楽しいカメラライフ。
ちなみに昨日名古屋に行ってきて雑に長時間露光を試してみました。こんな感じ。
総括
中古ガジェット沼、特定のなにかに沈めるものではなくていろんな沼と関連性があり、そして他の沼にズブズブ沈んでいってしまう危険性の高い激しい沼です(今更)。
純粋に楽しむという意味では昔話題になった珍ガジェットが流れてきているのを見て楽しんだり、なぜか業務用バーコードリーダーや病院で使われているらしい端末が売られているのを見て笑ったり、かなりバリエーションの有るものが見れます。
実用的に走ろうと思えば良い品を探して買ってみたり、ネタみたいなゴミ端末に思いを馳せたり、いろんな楽しみ方ができる不思議な沼でした。財布と時間の使い方には気をつけよう!
第51回情報科学若手の会を運営して参加してきた #wakate2018
表題の通りです。
10/6-8に軽井沢研修所というところで行われた第51回情報科学若手の会というイベントに幹事として参加しました。幹事なので運営もしているという感じですね。
幹事って何をしているの?とか若手の会のお金周りってどうなっているの?みたいな雰囲気だと、今回代表幹事を務めた @kuro_m88 さんが記事にまとめているのでそちらを見ると良さそうです。
幹事としては初めてなんですが、これまで学部3、4年、社会人1年目と3年続けて参加してきたのでこれで4年目4回目の参加という感じです。
セッションについて
上の @kuro_m88 さんの記事にも言及されている通り、情報科学若手の会においては幹事も参加者です。僕はカメラマンの真似事をしたりしながらだったのですが幹事もみんなセッションをずっと聞いていました。 僕情報科学若手の会というと、毎年アカデミックな方面で多方面に深い話題を話してくださる方が多いので、ネイティブアプリ開発一辺倒な僕としては首を縦に振りながら「こういう世界もあるんか…」みたいな感想を抱くことがほとんどという感じで、毎年同じことを言っている気がするのですがいろんな刺激を受けることができたなぁと思っています。
今回のセッションを大まかに分けると
という感じで、その中でも参加者の多数に「僕も私もデータセンターがほしい」と言わせた招待講演のコンテナデータセンターのお話がすごく盛り上がっていた印象があります。自身でデータセンターみたいな大きな設備を作り上げる過程がすごく夢(?)のあるお話でした。
僕個人としては高校生の方が二人発表されていて、結果としてはともかく抱えた課題を解決するためにWebサービスをDjangoで書いてたり、課題研究的な名目でIoTなことをされていてすごくものづくりにトライすることへのハードルが下がっていていいなぁ…と思ってました。高校生の時期からものづくり・プロトタイピングにチャレンジできるってすごく経験値としては貴重なものだと考えているので羨ましい限りでした。
毎年「来年は発表しよう」と意気込んでいるのですが、幹事と化したことで忙しさ++って状態になってしまい、特になにか思いつくこともなく…って感じでしたね。来年はなにか用意できるといいなぁって思う程度にしておきます。
交流イベントについて
今年はやる側ではなくやらせる(?)側になったのですが、今年のお題はnanoblockをチームで組み立ててドゥンする感じのアレでした。本当はnanoblockを組んでいる人は目隠しをする予定だったのですが、僕が目隠しをしたときに何もできなくなってすぐ諦めた経緯があります。本当に無理でしたね…。 テストプレイではnanoblockの説明書を見て指示側が言語化をする画像要約的ななにかと組む側が指示側の発言をなんとなく察していく機械学習的ななにかがあって面白かったのですが、皆さんめちゃくちゃ集中されていて茶々を入れる隙もなくてすごかったです。
ちなみに終盤の悲鳴を上げたチームの「単体テストは完璧なのに結合テストが通らない!!」が今回最大の名言だと思いました。nanoblockは開発プロジェクトなのではないかという一説を投じる素晴らしい言葉ではないでしょうか(?)
なんで若手の会に参加し続けているの?
この会に何を求めているのか、みたいな話なんですが、カンファレンスとか勉強会に参加するモチベーションと似ているような違うような、そんなよくわからない気持ちです。 カンファレンスや勉強会だと自分が専攻している・メインに扱っている分野の知見を深めたり、広めたりするようなモチベーションなのかなぁと僕個人のモチベーションとしてはあるのですが、こと情報科学若手の会においてはターゲットが「情報科学」という広い上にがっさりとしたテーマなので、それこそ本当に前述したようないろんな分野の人が来て、いろんなことを話しているんですよね。その中で「何も知らないことを知る」という無知の知を得て、もしその中で興味が生まれるようなことがあれば自分で深く調べてみたりとか、そういうきっかけになるといいなぁと参加しています。大体この会で発表してくださる人ってその分野のことを楽しそうに話されるのでそういう意味ではすごくいい刺激がもらえるなぁ、と思っています。
あとは僕を最初に若手の会に引き込んだ人が「人生をいい意味で狂わされた」と言っていたのですが、いろんな界隈のいろんなバックエンドの方が(お酒飲んで)ワイワイしているので色んなお話や相談ができてすごい、みたいな感じです。ゲラゲラ笑ってるだけかもしれないしすごく真面目に話し合ってたり、進路相談していたり。まさに今の開催理念に掲げている「ルイーダの酒場」な感じがしていていいなぁと思いました。なので来年も頑張っていくぞい、みたいな気持ちです。
初幹事だったけど
初幹事ということで5月に下見に行ったり、準備としてタスクが増えたり、いろいろイベントは増えたんですが当日はほぼ参加者みたいなノリで楽しめたなぁと思っています。閉会後も残ってた幹事で軽井沢ぶらついてビール飲んだり温泉入ったり霧の軽井沢駅でモカソフト食べたりしてました。 初めてだったのでよくわからないところは割とぽいっとしちゃって、できることだけをやってフォローに回ったりしてたんですが、多少慣れたはずなのでもうちょっと自分がテキパキ動けるようになるといいですね。はい。
今年は技術書典5と開催日がダブってしまった都合で、毎年いらっしゃってくれていた方々が来れなくなってしまったのが心残りでした…。来年はしっかりイベントスケジュールを立てていきたいですね。
おまけ
軽井沢の写真のせるマンになります。担々麺とビールめっちゃうまかった(感想)
写真を自動でアップロードする技術 〜Google Photos API編〜
アブストラクト
2018年のGoogle I/O直前にて公開されたGoogle Photos APIを使って一眼レフカメラで撮った写真をよしなに自動でアップロードするための手法録になります。
高専カンファレンスで大慌てで話していた発表を丁寧に焼き直そうとした感じになっています。
本記事ではGoogle Photos APIについてまとめます。スライド中で触れられている他の要素については別記事にて…。
Google Photos API
Google Photos APIs | Google Developers
我々(主語拡大)は君をずっと待っていた。
これまで名前だけになってしまったPicasa APIを使ってGoogle Photosへの画像アップロード(容量無制限無制限・16MPへの画像縮小制約あり)ができる環境はあったが、Google Photosにオリジナルサイズの画像の投稿が可能になったGoogle Photos APIがついにロンチされました。
トップページから入れるガイドページの概要を見る限りがっさりとした仕様では
- OAuth 2.0による認証
- Library
- ユーザのGoogle Photosアカウントに保存されるメディアについての操作ができるぞ!
- Albums
- ほかユーザと共有するためのアルバムに関する操作ができるぞ!
- Media Items
- Google Photosにおけるメディア(画像、動画)についての操作ができるぞ!
- 写真のアップロード自体はここに含まれる
- Share
- 自アカウントのメディアを他の人に共有するぞ!
と普通にGoogle Photosを使っている上での通り一遍の操作はできそうな印象があります。
というわけで今回は特に僕が達成したい「画像のGoogle Photos上へのアップロード」について記していきましょう。
というわけで本題。
Google Photos APIを使えるようにする。
いつものMaps等のGoogle APIsを使えるようにするプロセスとほぼ一緒ですね。まず、Google Cloud PlatformのコンソールからAPIの有効化を選び、API ライブラリ上でPhotos Library APIを検索すると、お目当てのPhotos Library APIが出てくるので有効化します。
有効化した後に「APIとサービス」のページに移動し、左ペインの認証情報を選んでから新規の認証情報としてOAuthクライアントIDを選択して作ればGoogle Cloud Platformのコンソールでの準備はOKです。僕は今回はAndroid(Android Things)からアップロードを試みていたので、この中でdebug.keystoreのようなkeystoreファイルのSHA1キーやApplication IDを入れたりしています。
Google Photos APIに画像を投稿してみる。
Google Photos API( https://photoslibrary.googleapis.com )における画像投稿は以下のようなシーケンスになっています。
- クライアントからGoogle Photos APIの
POST /v1/uploads
に対して画像をapplication/octet-stream
で送信する - Google Photos APIからレスポンスとしてアップロードトークンが返却される
- 返却されたアップロードトークンを含めてGoogle Photos APIの
POST /v1/mediaItems:batchCreate
にJSONを送信する - Google Photos APIから送信したJSONにGoogle Photos API内での情報が追加されレスポンスとして返却される = アップロード完了
ひとつずつ追っていきましょう。
1. 画像データの送信
なんてことはなく、/v1/uploads
に以下の内容のPOSTリクエストを送るだけです。
<Header> Authorization: Bearer <Token> Content-Type: application/octet-stream X-Goog-Upload-File-Name: <ファイル名> <Body> 画像のバイナリ
POSTが成功すると次のようなレスポンスが特に何かに包まれてるわけでもなく返却されます。この返却されている文字列がアップロードトークンになります。
CAIS6QIApKFirX.....
2. メディアアイテムを登録する
/v1/mediaItems:batchCreate
に先程手に入れたアップロードトークンを含めた次のjsonをbodyにしてPOSTリクエストを送ります。
<Header> Authorization: Bearer <Token> Content-Type: application/json <Body> {“newMediaItems”:[ { “simpleMediaItem":{ “uploadToken":"CAIS6QIApKFirX....." } } ]}
POSTが成功すると送ったjsonのパラメータにメタデータ等が肉付けされる感じで返却されます。この時点でGoogle Photosを確認するとアップロードされた写真が登録されているのが確認できます。
これで写真の投稿は完了です。この辺に関してはカメラで撮った写真とかに全く関係がないので写真によらない要素でも使えそうな気がします。アルバムとかの操作もできるのですが、それはまた別の機会に…。