Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Android Architecture Componentsを使ってリファクタリングした話
Search
Yoshihisa
June 26, 2018
Programming
1.8k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Android Architecture Componentsを使ってリファクタリングした話
shibuya.apk#26
Yoshihisa
June 26, 2018
More Decks by Yoshihisa
See All by Yoshihisa
OkHttp3+Retrofit2+...
yoshihisa
0
4.7k
Other Decks in Programming
See All in Programming
作るコストが小さくなった時代 幸せに働くために改めて考えたいこと 〜エンジニアとして価値を出し続けるために注視している二分野〜
yuppeeng
0
190
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
140
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
570
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
240
霧の中の代数的エフェクト
funnyycat
1
470
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
690
Apache Hive: Toward a Cloud Native Lakehouse
okumin
0
180
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
130
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.5k
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
170
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
170
Featured
See All Featured
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
350
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Into the Great Unknown - MozCon
thekraken
41
2.7k
A Tale of Four Properties
chriscoyier
163
24k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.9k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
370
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
WCS-LA-2024
lcolladotor
0
790
Fashionably flexible responsive web design (full day workshop)
malarkey
408
67k
Transcript
Android Architecture Componentsを 使ってリファクタリングした話
• Yoshihisa Takeda • Twitter: @bomneko_attack • 株式会社Diverse ◦ YYC
Androidアプリ開発 ◦ Androidデビューから1年経過 • 光の戦士 ◦ ララフェル♀ 白魔道士
メッセージ履歴画面 • ユーザ間のメッセージのやりとりをチャット風に表示する • ユーザの状態(性別/年齢確認(18歳以上かの確認)/これ までのやりとりの有無等)で表示が変わる ◦ スクショは女性で年齢確認済みかつ相手の男性にこれまでメー ルを送ったことがない人
(旧)構造 • Activity ◦ メッセージ履歴を表示する RecyclerView + Adapter ◦ ユーザのプロフィール取得
(写真とか性別とか) ◦ メッセージ取得 ◦ メッセージ送信 • メッセージ入力フォームFragment ◦ 各種のボタン(画像添付/スペシャルメール/テンプレート) ▪ スペシャルメールボタンをタップすると初回は説明表示があるため Activityにコールバック ◦ 入力フィールドと送信ボタン ▪ バリデーション ▪ 送信ボタンをタップすると Activityにコールバックされ送信される
(旧)構造
既にやばい香りがする
そこに… • Ver2.9.23: 女性向け新機能 スタンプ送信機能追加 • ただし条件付き ◦ 送信先は男性のみ ◦
送信先の男性に一度もメールを送ったことがない • UI ◦ スタンプのパレットをフォームの上に吹き出す感じで ◦ 入力フォームの切替ボタンを押すとパレットが開いたり閉じたり ◦ パレットが開いている状態だと切替ボタンの色が赤色になる
構造 • Activity ◦ メッセージ履歴を表示するRecyclerView + Adapter ◦ ユーザのプロフィール取得(写真とか性別とか) ◦
メッセージ取得 ◦ メッセージ送信 • メッセージ入力フォームFragment ◦ 各種のボタン(画像添付/スペシャルメール/テンプレート/スタンプパレット) ▪ スペシャルメールボタンをタップすると初回は説明表示があるためActivityにコールバック ▪ スタンプパレットボタンをタップするとパレットの表示切替のためActivityにコールバック ◦ 入力フィールドと送信ボタン ▪ バリデーション ▪ 送信ボタンをタップするとActivityにコールバックされ送信される • スタンプパレットFragment ◦ 送信できるスタンプをサーバから取得 ◦ スタンプをタップするとActivityにコールバックされ送信される
ver2.9.23構造
他にも… • 年齢確認の有無による表示切替 ◦ メッセージ本文が読めない (ブラーがかかる) ◦ メッセージの送信に制限がある
地獄爆誕
どうしてこんなことに… • 典型的なFat Activity • (当時)ActivityとFragmentでロジックと状態を共有するベストな解決策が思いつかな かった • リファクタリングに取り組む時間がなくこの仕組みの上に機能改修を行っていった
どうしてこんなことに… • 典型的なFat Activity • (当時)ActivityとFragmentでロジックと状態を共有するベストな解決策が思いつかな かった • リファクタリングに取り組む時間がなくこの仕組みの上に機能改修を行っていった Android
Architecture Components View Model + LiveData
ViewModel & LiveData • ViewModel(以下, VM) ◦ Activityが回転したときのデータ保持 ◦ 複数のフラグメント間とのデータ共有
• LiveData ◦ Lifecycleに従っていい感じにしてくれるデータホルダー ◦ Lifecycle OwnerがSTARTEDまたはRESUMEDのときのみアクティブになり値を通知してくれる ▪ 非同期処理でありがちな「処理が完了して値を通知し UIを操作しようとしたけれど非アクティ ブになっていてクラッシュ」がない
さぁやるぞ! • リファクタリングが失敗する要因 ◦ 既存のコードを理解しないまま手を付ける ◦ いきなり全部キレイにしようとする ◦ カッとなって全部書き直そうとする •
ひとまず手を付けるところを決めよう
方針 • まず送信に関係する状態とロジックをViewModelに分離することを目指す ◦ プロフィール取得・履歴取得とは独立していた ◦ 送信状態で取り得る状態は画面全体の表示状態と関連が薄かった ▪ 送信中は送信ボタンが消えて代わりにプログレスが表示される ▪
送信完了後スタンプパレットとスタンプパレット表示切り替えボタンを非表示にして履歴をリ ロードする • VMはステートマシンとして実装する ◦ 他の画面で実績があった ◦ 状態を保持するホルダーに LiveDataを使う ▪ (正直なところ)使ってみたかっただけ ▪ ライフサイクルに正しくバインドできれば Rxでも良い • 新規クラスのVM周りはKotlinで、既存クラスはJavaのまま我慢
状態の落とし込み 失敗したときに例外を一緒に持たせたいので enum classではなくsealed classで定義する
ViewModelの実装 • 使うLiveDataは2つ ◦ MutableLiveData: 内部ではコイツに値を postする. 外から値を変更されたくないので公開しない ◦ LiveData:
外部公開用. 使う側はコイツをObserveする ◦ 初期値はコンストラクタでセットしておく
• LiveDataが抱えている状態が「送信中」なら何もしない ◦ 「getValue」メソッドで今抱えている値を取り出せる • 送信中以外の場合は状態を「送信中」にセット • APIのレスポンスに応じて LiveDataに状態をセット ◦
setValue: UIスレッドのみ. IOスレッドで呼ぶと例外 ◦ postValue: IOスレッドでも使える ◦ このコードではIOスレッドで状態をセットするので「 postValue」
• ViewModelが死ぬときに呼び出される • サブスクリプションをクリアする等後始末をするのに使う
ViewModel Factory • ViewModelのコンストラクタに引数を渡すときに使う ◦ ViewModelは直接newしてはいけない
処理の移動と状態遷移の追跡 • ActivityのonCreateでVMを生成 • メッセージ入力フォームとスタンプパレットでActivityの送信メソッドを読んでいる箇 所をVMの送信メソッドを呼ぶように変更 • VMがもっている送信状態をActivityと各FragmentのそれぞれでObserveして状態 に応じてUI等を変更する処理を実装する
VMの初期化 • ActivityのonCreateでFactoryを指定してVMを生成 • VMの状態を抱えているLiveDataをObserveしてハンドリング ◦ Activityがアクティブでないと通知してこない • Javaにもwhen式とスマートキャストをくれ
FragmentでVMを使う • 親Activityがオーナーになっている送信 VMを取得する • FragmentでもVMの状態をハンドリングする • Javaにもwhen式とスマートキャストをくれ(大事なことなので(ry)
ver2.9.23構造
リファクタ後の構造
リファクタリングの結果 • 送信に関する責務をVMに追い出し ◦ 各FragmentはVMが抱えている状態を監視して表示などを変更するように (多少は)キレイになった!!!!
送信機能以外の部分について • プロフィール・メッセージ履歴取得部分についても 同様のアプローチでリファクタリングした ◦ プロフィールとメッセージ履歴は画面表示の状態に密に関連していたので 1つのVM • Activityの行数: 651
ー> 488 ◦ Activityが抱えていたInput Form FragmentやStamp Palette Fragmentの状態決定を それぞれのFragmentで行うように ◦ 機能の追加・改修もある程度しやすくなった (はず)
None
まとめ • Android Architecture Components ViewModelはいいぞ ◦ Activityの回転時のデータ保持 ◦ Fragment間のデータ共有
• リファクタリングするときは方針を決めよう ◦ ときには泥臭く地道にやっていきも大事 ◦ 進めているうちにさらに良い解が見つかることもあるので随時軌道修正
参考資料 • Architecture Components https://developer.android.com/topic/libraries/architecture/ ◦ ViewModel https://developer.android.com/topic/libraries/architecture/viewmodel ◦ LiveData
https://developer.android.com/topic/libraries/architecture/livedata