Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
個人開発AndroidアプリをKotlinにガチ移行してみた話
きりみん
June 05, 2015
Technology
9
7.1k
個人開発AndroidアプリをKotlinにガチ移行してみた話
きりみん
June 05, 2015
Tweet
Share
More Decks by きりみん
See All by きりみん
AndroidエンジニアがRailsにチャレンジしてる理由
kirimin
1
1.2k
What are AtCoder and competitive programming
kirimin
0
9.2k
バーチャル男声幼女プログラマーとして活動した1年間の振り返り
kirimin
0
730
アプリエンジニアでも神絵師になりたい!
kirimin
4
4.8k
Watashi ni Kotlin ga maiorita
kirimin
0
340
NEMのAPIとモザイクであそぼう
kirimin
0
320
はじめようきれいなコード
kirimin
8
2.8k
Material Components for Android触ってみる
kirimin
7
1.6k
[社内LT]あたらしいMaterial Design
kirimin
1
1.5k
Other Decks in Technology
See All in Technology
AI Company
shurain
0
470
成長を続ける組織でのSRE戦略:プレモーテムによる信頼性の認識共有 SRE Next 2022
niwatakeru
7
2.8k
アルプでのAgile Testing / Alp Agile Testing
nametake
0
210
Data Warehouse or Data Lake, which one do I choose?
ahana
0
130
事業の成長と共に歩む、ABEMA SRE探求の歴史 / SRE-Next 2022
nagaa052
0
390
IDOLY PRIDEにおけるAssetBundleビルドパイプラインについて
qualiarts
0
320
失敗から学ぶAWSコスト管理入門 ~想定の50倍以上の請求がきた話~
msato
0
440
エンタープライズにおけるSRE立ち上げとNew Relic選定に至った背景とは / SRE Startup and New Relic in the Enterprise
tomoyakitaura
2
160
新規ゲームのリリース(開発)前からのSRE活動
tmkoikee
1
460
1,000万人以上が利用する「家族アルバム みてね」のSRE組織は4年間でどのように作られてきたのか/SRE NEXT 2022
isaoshimizu
6
3.3k
LIFF Deep Dive 2022
line_developers
PRO
1
620
プロダクトグロースと技術のベースアップを両立させるRettyのアプリ開発スタイル / Achieve Product Growth and Tech Update
imaizume
1
300
Featured
See All Featured
Docker and Python
trallard
27
1.5k
The Brand Is Dead. Long Live the Brand.
mthomps
45
2.7k
Designing the Hi-DPI Web
ddemaree
272
32k
How To Stay Up To Date on Web Technology
chriscoyier
780
250k
Pencils Down: Stop Designing & Start Developing
hursman
112
9.8k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
19
1.4k
Building Better People: How to give real-time feedback that sticks.
wjessup
343
17k
Web development in the modern age
philhawksworth
197
9.3k
Java REST API Framework Comparison - PWX 2021
mraible
PRO
11
4.6k
BBQ
matthewcrist
74
7.9k
The Cult of Friendly URLs
andyhume
68
4.7k
Three Pipe Problems
jasonvnalue
89
8.6k
Transcript
個人開発Androidアプリを Kotlinにガチ移行してみた話 2015/6/5 第3回 かわいいKotlin勉強会 @kirimin
自己紹介 @kirimin • Androidアプリ開発者 (ジャバ) • エンジニア4年目 フリーランス2年目 • 現在は圧倒的当事者意識で某社の
Androidアプリ開発を手伝っています
自己紹介
None
今、Androidで Kotlinがアツい!!!!
なぜAndroidでKotlin?
なぜAndroidでKotlin?(おさらい) • AndroidではJava8が当分使えなそう • Kotlinならラムダ式もパイプラインでのリスト操作も書ける • RxAndroidとも相性が良い • Android StudioならIDEのサポートが効きすぐに使える
• 学習コストも低く、静的で安全志向な言語仕様は Androidエンジニアに丁度いい(主観) • Scalaはいろんな意味で人類にはまだ早い
KotlinでAndroid開発がしたい!!!
でも、本当に使えるのだろうか?
ならば既存アプリを全力で Kotlin化してみよう!!!
今回Kotlin化したアプリ https://play.google.com/store/apps/details?id=me.kirimin.mitsumine
mitsumine
mitsumine • 約3500行 • 54クラス • 使用しているライブラリ • RxAndroid •
Volley • ActiveAndroid • Picasso など...
やったこと • Kotlin利用準備 • JavaクラスをひたすらKotlin化 • Kotlin Android Extensionsを導入 •
もっとKotlinらしくしてみる
やったこと • Kotlin利用準備 • JavaクラスをひたすらKotlin化 • Kotlin Android Extensionsを導入 •
もっとKotlinらしくしてみる
Kotlin利用準備 • Android StudioにKotlinプラグインをインストール • build.gradleにおまじないを記述 だいたいこれだけ。 しかも.ktファイルを作るとポップアップが出てきて自動で やってくれる。
やったこと • Kotlin利用準備 • JavaクラスをひたすらKotlin化 • Kotlin Android Extensionsを導入 •
もっとKotlinらしくしてみる
JavaクラスをひたすらKotlin化 「Convert Java to Kotlin File」でひたすらポチポチ…
JavaクラスをひたすらKotlin化 「Convert Java to Kotlin File」でひたすらポチポチ… • クラス数が多いと結構だるい… (一斉変換も出来るけど) • 大抵は自動変換しただけでちゃんと動く
• 時々コンパイルエラーが出る • 時々実行時エラーが出る • 時々変な変換されて処理が消える • 1クラス変換する度にDiffって動作確認した方がハマらない(戒め)
JavaクラスをひたすらKotlin化 変換時に遭遇したエラーの思い出 • Null許容型とNull非許容型で型エラーが出てる →型に?を付けてNull許容型に変えたりして頑張ろう • overrideメソッドのsuperでエラーが出てる →super<Fragment>のようにどのスーパークラスを呼ぶのか 明示しよう •
CustomViewのコンストラクタでエラーが出てる →class xxxView: View()の()を消してsecondary constructor の構文を使おう
• Kotlin利用準備 • JavaクラスをひたすらKotlin化 • Kotlin Android Extensionsを導入 • もっとKotlinらしくしてみる
やったこと
Kotlin Android Extensionsを導入 Kotlin Android Extensionsとは • KotlinのAndroid用公式ライブラリ(プラグイン) • findViewByIdを葬り去るためのライブラリ
• Activityクラスのimport文でActivityとレイアウトファイルを紐 付けるだけでActivityにViewのプロパティを生やしてくれる • Butter Knifeの@InjectViewすら必要ない版のようなイメージ • 手軽に使えてめちゃくちゃ便利
Kotlin Android Extensionsを導入 import kotlinx.android.synthetic.<layout>.* ActivityやFramentにレイアウトファイルを紐付ける。 userNameTextView.setText(“test”); Activityのプロパティになるのでそのまま参照出来る。 getView().userNameTextView.setText(“test”); Fragmentの場合はgetView()で取得出来るルートのViewに生える。
• Kotlin利用準備 • JavaクラスをひたすらKotlin化 • Kotlin Android Extensionsを導入 • もっとKotlinらしくしてみる
やったこと
もっとKotlinらしくしてみる 匿名クラスをラムダ式に書き換える textView.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View)
{ } }) textView.setOnClickListener { v -> } ↓
もっとKotlinらしくしてみる 匿名クラスのままKotlinに変換されたRxJavaの処理も subscriptions.add(EntryInfoApi.request(RequestQueueSingleton.get(getApplicationContext()), url) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .map<EntryInfo>(EntryInfoFunc.mapToEntryInfo()) .filter(object : Func1<EntryInfo,
Boolean> { override fun call(entryInfo: EntryInfo?): Boolean? { return entryInfo == null } }) .subscribe(object : Action1<EntryInfo> { override fun call(entryInfo: EntryInfo) { countLayout.setVisibility(View.VISIBLE) titleTextView.setText(entryInfo.getTitle()) bookmarkCountTextView.setText(String.valueOf(entryInfo.getBookmarkCount())) Picasso.with(getApplicationContext()).load(entryInfo.getThumbnailUrl()).fit().into(thumbnailImageView) val adapter = EntryInfoPagerAdapter(getSupportFragmentManager()) adapter.addPage(BookmarkListFragment.newFragment(entryInfo.getBookmarkList()), getString(R.string.entry_info_all_bookmarks)) subscriptions.add(Observable.from<Bookmark>(entryInfo.getBookmarkList()) .filter(EntryInfoFunc.hasComment()) .toList() .subscribe(object : Action1<List<Bookmark>> { override fun call(commentList: List<Bookmark>) { commentCountTextView.setText(String.valueOf(commentList.size())) adapter.addPage(BookmarkListFragment.newFragment(commentList), getString(R.string.entry_info_comments)) if (AccountDAO.get() != null) { adapter.addPage(RegisterBookmarkFragment.newFragment(entryInfo.getUrl()), getString(R.string.entry_info_register_bookmark)) } viewPager.setAdapter(adapter) viewPager.setCurrentItem(1) viewPager.setOffscreenPageLimit(2) tabs.setViewPager(viewPager) } })) } }, object : Action1<Throwable> { override fun call(throwable: Throwable) { Toast.makeText(getApplicationContext(), R.string.network_error, Toast.LENGTH_SHORT).show() }
もっとKotlinらしくしてみる 全てラムダ式にしてスッキリ! subscriptions.add(EntryInfoApi.request(RequestQueueSingleton.get(getApplicationContext()), url) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .map { response ->
EntryInfoFunc.toEntryInfo(response) } .filter { entryInfo -> !entryInfo.isNullObject() } .subscribe ({ entryInfo -> countLayout.setVisibility(View.VISIBLE) titleTextView.setText(entryInfo.title) bookmarkCountTextView.setText(entryInfo.bookmarkCount.toString()) Picasso.with(getApplicationContext()).load(entryInfo.thumbnailUrl).fit().into(thumbnailImageView) val adapter = EntryInfoPagerAdapter(getSupportFragmentManager()) adapter.addPage(BookmarkListFragment.newFragment(entryInfo.bookmarkList), getString(R.string.entry_info_all_bookmarks)) subscriptions.add(Observable.from<Bookmark>(entryInfo.bookmarkList) .filter { bookmark -> EntryInfoFunc.hasComment(bookmark) } .toList() .subscribe { commentList -> commentCountTextView.setText(commentList.size().toString()) adapter.addPage(BookmarkListFragment.newFragment(commentList), getString(R.string.entry_info_comments)) AccountDAO.get()?.let { adapter.addPage(RegisterBookmarkFragment.newFragment(entryInfo.url), getString(R.string.entry_info_register_bookmark)) } commentsViewPager.setAdapter(adapter) commentsViewPager.setCurrentItem(1) commentsViewPager.setOffscreenPageLimit(2) tabs.setViewPager(commentsViewPager) }) }, { Toast.makeText(getApplicationContext(), R.string.network_error, Toast.LENGTH_SHORT).show() })
もっとKotlinらしくしてみる リスト操作を高階関数に書き換える for (i in list) { if (i %
2 == 0) { System.out.print(i) } } list.filter { i -> i % 2 == 0 } .forEach { i -> System.out.print(i) } ↓
もっとKotlinらしくしてみる Callback用の自前Interface(trait)も public trait TestCallback { public fun onSuccess(callback: Int)
} public fun request(callback: TestCallback) { callback.onSuccess(200) } // 呼び出し元 test.request(object : Test.TestCallback { override fun onSuccess(callback: Int) { } })
もっとKotlinらしくしてみる 高階関数で直接処理を受け取ればシンプルに出来ます public fun request(onSuccess: (callback: Int) -> Unit) {
onSuccess(200) } // 呼び出し元 test.request { callback -> }
まとめ
まとめ • Kotlin置換+αの対応だけで3500行→3000行くらいにコード をスリム化! • Javaで設計されたコードの移行はわりと大変だった (単純置換だけだとかえって読みにくいコードになるかも) • とはいえAndroidアプリの開発をガッツリKotlinでやる事自体 の不便さや辛さはほとんど感じなかった
(ライブラリなどもそのまま使えたよ) • むしろ一度Kotlinを味わうとAndroidJavaでリスナーや リスト操作を書くのが辛くなる
まとめ • 個人開発の新規アプリや期間限定の出し切りアプリなどであれ ばKotlinは現実的な選択肢では • 個人開発の既存アプリを書き換えるべきかはモチベーション 次第だけどメリットは十分あると思う • 業務で導入する場合、標準じゃない技術に依存するリスクを メリットが上回るかは………
まとめ • 詳しい知見はコードをご確認ください https://github.com/kirimin/mitsumine
誰か業務で使った実績 でっち上げてくれ!!!!
ご清聴ありがとうございました!