Slide 1

Slide 1 text

今からはじめる Android Kotlin あんざいゆき(@yanzm) Kotlin Fest 2019

Slide 2

Slide 2 text

Yuki Anzai • Android App Developer (2009~) • CEO of uPhyca Inc. (2011~) • Google Developers Expert for Android • Organizer of GTUG Girls and droid girls • Twitter : @yanzm

Slide 3

Slide 3 text

Master of Dagger • Dagger 解説本 • 出てくるコードは全部 Kotlin • 技術書典7 (9⽉22⽇) • TechBooster

Slide 4

Slide 4 text

Android Kotlin • 2017年の Google I/O で Kotlin が Android 開発の公式サポート⾔語の1 つになることが発表された

Slide 5

Slide 5 text

Android Kotlin • 2017年の Google I/O で Kotlin が Android 開発の公式サポート⾔語の1 つになることが発表された • Professional Android developers の 50% 以上が Kotlin を使っている (Google I/O 2019 より)

Slide 6

Slide 6 text

Android Kotlin • 2017年の Google I/O で Kotlin が Android 開発の公式サポート⾔語の1 つになることが発表された • Professional Android developers の 50% 以上が Kotlin を使っている (Google I/O 2019 より) • If you're starting a new project, you should write it in Kotlin; https://android-developers.googleblog.com/2019/05/google-io-2019- empowering-developers-to-build-experiences-on-Android-Play.html

Slide 7

Slide 7 text

公式サイト • Kotlin lang • https://kotlinlang.org/docs/tutorials/kotlin-android.html • Android Developers • https://developer.android.com/kotlin

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Android プロジェクトで Kotlin を使えるようにする

Slide 11

Slide 11 text

Kotlin Plugin • Android Studio 3.0 以降は最初から⼊っている

Slide 12

Slide 12 text

新規プロジェクトで Kotlin を使う • [File] - [New] - [New Project...] Android Studio 3.5

Slide 13

Slide 13 text

Android Studio 3.5

Slide 14

Slide 14 text

Android Studio 3.5

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

既存プロジェクトで Kotlin を使う • Android Studio に設定を追加してもらう⽅法 • ⼿動で設定を追加する⽅法

Slide 17

Slide 17 text

Android Studio に設定を追加してもらう⽅法 ① • 1. [Tools] - [Kotlin] - [Configure Kotlin in Project] • 2. Android with Gradle

Slide 18

Slide 18 text

• 3. [All modules] または [Single module] を選択して OK をクリックする Android Studio に設定を追加してもらう⽅法 ①

Slide 19

Slide 19 text

Android Studio に設定を追加してもらう⽅法 ② • 1. Kotlin ファイルを追加すると「Kotlin not configured」というメッ セージが出るので Configure をクリックする

Slide 20

Slide 20 text

Android Studio に設定を追加してもらう⽅法 ② • 2. [All modules] または [All modules containing Kotlin files] を選択し て OK をクリックする

Slide 21

Slide 21 text

プロジェクト の build.gradle

Slide 22

Slide 22 text

モジュール の build.gradle

Slide 23

Slide 23 text

モジュール の build.gradle を修正する

Slide 24

Slide 24 text

⼿動で設定を追加する⽅法 • プロジェクトの build.gradle とモジュールの build.gradle に必要な設定 を追加する

Slide 25

Slide 25 text

プロジェクトの build.gradle

Slide 26

Slide 26 text

モジュール の build.gradle 必須 使わないなら不要 必須 使わないなら不要

Slide 27

Slide 27 text

Android Library モジュールで Kotlin を使う • build.gradle の設定は Android application モジュールと同じ • kotlin-android plugin • kotlin-android-extensions plugin (任意) • kotlin-stdlib-jkd7 • core-ktx (任意)

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

Library モジュールで Kotlin を使う • Kotlin Library モジュール • New Module ウィザードには Java Library しかないので、Java Library を Kotlin Library に変換する

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

モジュール の build.gradle を修正する

Slide 33

Slide 33 text

Java Library と同じように dependencies に追加できる

Slide 34

Slide 34 text

Kotlin Style Guide

Slide 35

Slide 35 text

Kotlin Style Guide • Kotlin lang • https://kotlinlang.org/docs/reference/coding-conventions.html • Android Developers • https://developer.android.com/kotlin/style-guide • Kotlin コードに対するの Google’s Android coding standards

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Code Style • [Preferences] - [Editor] - [Code Style] - [Kotlin]

Slide 38

Slide 38 text

Kotlin style guide に合わせる

Slide 39

Slide 39 text

ktlint • Kotlin コードのフォーマットに対する linter • チームで PR時にフォーマットのチェックを強制したいときに便利 • https://github.com/pinterest/ktlint

Slide 40

Slide 40 text

Java コードを Kotlin に 変換する

Slide 41

Slide 41 text

Java と Kotlin の共存 • Java コードと Kotlin コードはプロジェクトで共存できる • テストコードだけ Kotlin にしてみる • 新規のコードは Kotlin で書く • 既存コードを徐々に Kotlin に変えていく

Slide 42

Slide 42 text

Java と Kotlin の共存 • Java コードと Kotlin コードはプロジェクトで共存できる • テストコードだけ Kotlin にしてみる • 新規のコードは Kotlin で書く • 既存コードを徐々に Kotlin に変えていく • 既存の Java コードを Kotlin に変換する作業は Kotlin の学習効率がよい (個⼈の感想です)

Slide 43

Slide 43 text

Java → Kotlin • 1. [Code] - [Convert Java File to Kotlin File] で Kotlin に変換する • 2. 変換後のコードを修正する • !! を ?:, ?.let, lateinit, by などへ書き換える • 標準関数や KTX や Kotlin Android Extensions などを使うようにする

Slide 44

Slide 44 text

Kotlin ファイルに Java コードをコピペ • Java コードを Kotlin ファイルにコピペすると⾃動で Kotlin コードに変 換されて貼り付けられる • 設定で Kotlin に変換させないようにすることもできる

Slide 45

Slide 45 text

[Preference] - [Editor] - [General] - [Smart Keys] Java コード を Kotlin ファイルにペーストしたときに Kotlin に変換するかどうか ペースト時に Kotlin に変換するか確認する ダイアログを出すかどうか

Slide 46

Slide 46 text

気をつけること

Slide 47

Slide 47 text

Convert Java to Kotlin • 愚直な変換 • !!などが残る • !! を ?:, ?.let, lateinit, by などへ書き換える • 便利な標準関数などは使われない • Kotlin の標準関数は⼀通りチェックしよう • https://kotlinlang.org/api/latest/jvm/stdlib/index.html

Slide 48

Slide 48 text

Convert Java to Kotlin • 愚直な変換 • !!などが残る • !! を ?:, ?.let, lateinit, by などへ書き換える • 便利な標準関数などは使われない • Kotlin の標準関数は⼀通りチェックしよう • https://kotlinlang.org/api/latest/jvm/stdlib/index.html kotlin.collections kotlin.text パッケージの関数は チェックしよう

Slide 49

Slide 49 text

Platform type • 昔の Android Framework コードには @NonNull, @Nullable アノテー ションがついていない • null が返る可能性に注意しよう

Slide 50

Slide 50 text

よくある(?)誤解

Slide 51

Slide 51 text

よくある(?)誤解 • プロジェクトの最初から Kotlin にしないといけない? • → 既存の Java プロジェクトでも Kotlin を使うことができる • 全て Kotlin にしないといけない? • → Java コードと Kotlin コードの両⽅をプロジェクトで使えます • Kotlin から既存の Java クラスは使えない? • → 使えます

Slide 52

Slide 52 text

よくある(?)誤解 • 既存の Java コードから Kotlin のクラスは使えない? • → 使えます • Java のライブラリは Kotlin から使えない? • → 使えます

Slide 53

Slide 53 text

Kotlin Annotation processing tool

Slide 54

Slide 54 text

Kotlin でアノテーションを使うには • Annotation Processing を使っている Java コードを Kotlin に変換する とエラーになった、どうすれば? • Kotlin で書くことになった新規コードで Annotation Processing を利⽤ するライブラリを使いたいがどうすれば?

Slide 55

Slide 55 text

Kotlin でアノテーションを使うには • Annotation Processing を使っている Java コードを Kotlin に変換する とエラーになった、どうすれば? • Kotlin で書くことになった新規コードで Annotation Processing を利⽤ するライブラリを使いたいがどうすれば? kapt を使う https://kotlinlang.org/docs/tutorials/android-frameworks.html

Slide 56

Slide 56 text

... apply plugin: 'kotlin-kapt' android { ... } dependencies { ... implementation "com.google.dagger:dagger:$dagger_version" kapt "com.google.dagger:dagger-compiler:$dagger_version" } モジュール の build.gradle

Slide 57

Slide 57 text

Kotlin Android Extensions

Slide 58

Slide 58 text

Kotlin Android Extensions • Android Studio (IntelliJ IDEA)の Kotlin plugin に含まれる機能

Slide 59

Slide 59 text

... apply plugin: 'kotlin-android-extensions' android { ... } ... モジュール の build.gradle

Slide 60

Slide 60 text

Kotlin Android Extensions • View binding • Parcelable implementations generator

Slide 61

Slide 61 text

View binding • レイアウト XML 内の View にアクセスするための Activity の拡張プロパ ティを⽣成する

Slide 62

Slide 62 text

activity_main.xml

Slide 63

Slide 63 text

... class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById(R.id.textView).text = "Hello, world!" } } MainActivity : findViewById 利⽤

Slide 64

Slide 64 text

... import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) textView.text = "Hello, world!" } } MainActivity

Slide 65

Slide 65 text

import kotlinx.android.synthetic.main.fragment_main.* class MainFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_main, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) textView.text = "Hello, world!" } } Fragment

Slide 66

Slide 66 text

import kotlinx.android.synthetic.main.view_custom.view.* class CustomView : LinearLayout { ... init { View.inflate(context, R.layout.view_custom, this) textView.text = "Hello, world!" } } View z

Slide 67

Slide 67 text

View binding • レイアウト XML 内の View にアクセスするための Activity の拡張プロパ ティを⽣成する • Container で View をキャッシュする • Container = Kotlin で書かれた Activity, Fragment, View, LayoutContainer を実装したクラス

Slide 68

Slide 68 text

public final class MainActivity extends AppCompatActivity { private HashMap _$_findViewCache; protected void onCreate(@Nullable Bundle savedInstanceState) { ... } public View _$_findCachedViewById(int var1) { if (this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(var1); if (var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(var1, var2); } return var2; } ... }

Slide 69

Slide 69 text

View binding • レイアウト XML 内の View にアクセスするための Activity の拡張プロパ ティを⽣成する • Container で View をキャッシュする • Container = Kotlin で書かれた Activity, Fragment, View, LayoutContainer を実装したクラス • LayoutContainer (experimental)

Slide 70

Slide 70 text

experimental 設定 apply plugin: 'kotlin-android-extensions' android { ... } androidExtensions { experimental = true } ... モジュール の build.gradle

Slide 71

Slide 71 text

import kotlinx.android.synthetic.main.list_item.view.* class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { fun bind(message: String) { itemView.textView.text = message } } LayoutContainer なし textView にアクセスできるがキャッシュされない

Slide 72

Slide 72 text

public final class MyViewHolder extends ViewHolder { public final void bind(@NotNull String message) { Intrinsics.checkParameterIsNotNull(message, "message"); View var10000 = this.itemView; Intrinsics.checkExpressionValueIsNotNull(var10000, "itemView"); TextView var2 = (TextView)var10000.findViewById(id.textView); Intrinsics.checkExpressionValueIsNotNull(var2, "itemView.textView"); var2.setText((CharSequence)message); } public MyViewHolder(@NotNull View view) { Intrinsics.checkParameterIsNotNull(view, "view"); super(view); } }

Slide 73

Slide 73 text

LayoutContainer あり public interface LayoutContainer { /** Returns the root holder view. */ public val containerView: View? }

Slide 74

Slide 74 text

import kotlinx.android.synthetic.main.list_item.* class MyViewHolder( override val containerView: View ) : RecyclerView.ViewHolder(containerView), LayoutContainer { fun bind(message: String) { textView.text = message } } LayoutContainer あり キャッシュされる

Slide 75

Slide 75 text

public final class MyViewHolder extends ViewHolder implements LayoutContainer { @NotNull private final View containerView; private HashMap _$_findViewCache; ... public View _$_findCachedViewById(int var1) { if (this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(var1); if (var2 == null) { View var10000 = this.getContainerView(); if (var10000 == null) { return null; } var2 = var10000.findViewById(var1); this._$_findViewCache.put(var1, var2); } return var2; } ... }

Slide 76

Slide 76 text

Parcelable implementations generator • experimental apply plugin: 'kotlin-android-extensions' android { ... } androidExtensions { experimental = true } ...

Slide 77

Slide 77 text

Parcelable implementations generator • experimental • @Parcelize がついたクラスの Parcelable 実装を⾃動⽣成する • primitive types や String, enum , objects などサポートしている型は多 い • サポートしていない型に対しては Custom Parceler で対応できる https://kotlinlang.org/docs/tutorials/android-plugin.html#parcelable-implementations-generator

Slide 78

Slide 78 text

class User(val name: String, val age: Int) : Parcelable { override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeString(name) parcel.writeInt(age) } override fun describeContents(): Int = 0 companion object CREATOR : Parcelable.Creator { override fun createFromParcel(parcel: Parcel): User = parcel.run { User(readString()!!, readInt()) } override fun newArray(size: Int): Array = arrayOfNulls(size) } } ⾃前で実装した場合

Slide 79

Slide 79 text

@Parcelize class User(val name: String, val age: Int) : Parcelable @Parcelize を使った場合

Slide 80

Slide 80 text

@Parcelize public final class User implements Parcelable { ... public static final android.os.Parcelable.Creator CREATOR = new User.Creator(); ... public void writeToParcel(@NotNull Parcel parcel, int flags) { Intrinsics.checkParameterIsNotNull(parcel, "parcel"); parcel.writeString(this.name); parcel.writeInt(this.age); } ... public static class Creator implements android.os.Parcelable.Creator { @NotNull public final Object[] newArray(int size) { return new User[size]; } @NotNull public final Object createFromParcel(@NotNull Parcel in) { Intrinsics.checkParameterIsNotNull(in, "in"); return new User(in.readString(), in.readInt()); } } }

Slide 81

Slide 81 text

KTX

Slide 82

Slide 82 text

Android KTX とは • Android Jetpack • Android Framework や AndroidX 向けの Kotlin extensions 集 • 拡張関数・拡張プロパティ・ラムダ・名前付き引数・引数のデフォルト値 • core, activity, fragment, viewModel, workManager など様々なライブラ リ向けの ktx がある • https://developer.android.com/kotlin/ktx

Slide 83

Slide 83 text

core-ktx • Android Framework の API に対する extensions 集 • androidx.core:core-ktx:$version sharedPreferences .edit() .putBoolean("key", value) .apply() sharedPreferences.edit { putBoolean("key", value) }

Slide 84

Slide 84 text

activity-ktx • ComponentActivity に対する extensions 集 • androidx.activity:activity-ktx:$version class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by viewModels() ... }

Slide 85

Slide 85 text

fragment-ktx • Fragment に対する extensions 集 • androidx.fragment:fragment-ktx:$version class MainFragment : Fragment() { private val viewModel: MainViewModel by viewModels() private val viewModel2: MainViewModel by activityViewModels() ... }

Slide 86

Slide 86 text

livedata-ktx • Android Architecture Components の LiveData に対する extensions 集 • androidx.lifecycle:lifecycle-livedata-ktx:$version class MainViewModel : ViewModel() { private val _data = MutableLiveData() val data: LiveData get() = _data.distinctUntilChanged() }

Slide 87

Slide 87 text

viewmodel-ktx • Android Architecture Components の ViewModel に対する extensions 集 • androidx.lifecycle:lifecycle-viewmodel-ktx:$version class MainViewModel : ViewModel() { fun load() { viewModelScope.launch { ... } } }

Slide 88

Slide 88 text

KTX との付き合い⽅ • ⼤事なのは KTX の存在を知っていて、必要なときは調べられること • Android のサンプルコード • Web 上のコンテンツ • チームのコード

Slide 89

Slide 89 text

KTX の extensions を調べる • Reference ドキュメントの パッケージ Overview の 「Extension functions summary」「Extension functions」を⾒る

Slide 90

Slide 90 text

Android Studio の Kotlin 関係 の機能

Slide 91

Slide 91 text

Tools - Kotlin

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

Kotlin plugin channel • [Tools] - [Kotlin] - [Configure Kotlin Plugin Updates] または [Preferences] - [Languages & Frameworks] - [Kotlin]

Slide 94

Slide 94 text

Kotlin plugin channel • [Tools] - [Kotlin] - [Configure Kotlin Plugin Updates] または [Preferences] - [Languages & Frameworks] - [Kotlin]

Slide 95

Slide 95 text

Kotlin REPL • [Tools] - [Kotlin] - [Kotlin REPL] • 対話モードで Kotlin コードを実⾏できる

Slide 96

Slide 96 text

Show Kotlin Bytecode • [Tools] - [Kotlin] - [Show Kotlin Bytecode] • Kotlin Bytecode がみれる

Slide 97

Slide 97 text

Show Kotlin Bytecode • Decompile ボタンを押すと decompile された Java コードがみれる

Slide 98

Slide 98 text

その他設定 & 便利機能

Slide 99

Slide 99 text

Color Scheme • [Preferences] - [Editor] - [Color Scheme] - [Kotlin]

Slide 100

Slide 100 text

Color Scheme • [Preferences] - [Editor] - [Color Scheme] - [Kotlin] ⽩系のDefault →

Slide 101

Slide 101 text

Color Scheme • [Preferences] - [Editor] - [Color Scheme] - [Kotlin] 黒系のDarcula →

Slide 102

Slide 102 text

Inspections • [Preferences] - [Editor] - [Inspections] • [Analyze] - [Inspect Code...] でチェックする 項⽬とそのレベル設定

Slide 103

Slide 103 text

Intentions • [Preferences] - [Editor] - [Intensions]

Slide 104

Slide 104 text

File and Code Templates • [Preferences] - [Editor] - [File and Code Templates] • ファイルとコードのテン プレートをカスタマイズ できる

Slide 105

Slide 105 text

No content

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

No content

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

No content

Slide 111

Slide 111 text

Postfix Completion • [Preferences] - [Editor] - [General] - [Postfix Completion] • キーワードの接尾辞をつけ て tab を押すとコードが補 完される

Slide 112

Slide 112 text

list.for tab for (i in list) { } 例)for

Slide 113

Slide 113 text

Live Templates • [Preferences] - [Editor] - [Live Templates] • キーワードの略語をタイ プして tab を押すとテン プレートコードが挿⼊さ れる

Slide 114

Slide 114 text

fun1 tab fun (x: Any): Unit { } 例)fun1

Slide 115

Slide 115 text

Language Injections • [Preferences] - [Editor] - [Language Injections] • ⽂字列を別の⾔語と認識 して編集できる機能

Slide 116

Slide 116 text

// language=RegExp val pattern = "[a-z]+" ⽅法1) language= @Language("RegExp") val pattern = "[a-z]+" ⽅法2) @Language ⽅法3) Kotlin で⾃動認識されるパターン val pattern = "[a-z]+".toRegex() val pattern2 = Regex("[a-z]+")

Slide 117

Slide 117 text

// language=RegExp val pattern = "[a-z]+" ⽅法1) language= @Language("RegExp") val pattern = "[a-z]+" ⽅法2) @Language ⽅法3) Kotlin で⾃動認識されるパターン val pattern = "[a-z]+".toRegex() val pattern2 = Regex("[a-z]+")

Slide 118

Slide 118 text

まとめ

Slide 119

Slide 119 text

まとめ • 新規プロジェクトは Kotlin!既存プロジェクトも Kotlin 化を進めたほうが 恩恵を受けられる • Kotlin first な Android の取り組みが増えてきている(nullability annotation, KTX, Jetpack Compose) • Java と Kotlin のコードはプロジェクトで共存できる • Kotlin は Java と interoperability があるから安⼼して Kotlin を始めよう

Slide 120

Slide 120 text

おわり