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
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
200
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
2
420
ソフトウェアラスタライザ
fadis
1
480
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
350
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
240
Loosening the Reins: Go Generics Get More Flexible
kuro_kurorrr
0
270
Flow は今どうなっているか
mizdra
PRO
0
670
Cloudflare is Agents
chimame
0
180
AI Readyの正体はデータマネジメントだ メダリオン2.0の最前線
freee
PRO
0
360
Dockerfile CMD for Node.js
grazie1999
0
110
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
240
FastAPI の並行処理モデルを完全に理解する
hoto17296
8
2.7k
Featured
See All Featured
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
260
YesSQL, Process and Tooling at Scale
rocio
174
15k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
900
The SEO identity crisis: Don't let AI make you average
varn
0
530
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
380
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
30 Presentation Tips
portentint
PRO
1
370
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
280
Crafting Experiences
bethany
1
260
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