Upgrade to Pro — share decks privately, control downloads, hide ads and more …

今からはじめる Android Kotlin

Yuki Anzai
August 24, 2019

今からはじめる Android Kotlin

Yuki Anzai

August 24, 2019
Tweet

More Decks by Yuki Anzai

Other Decks in Technology

Transcript

  1. 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
  2. Android Kotlin • 2017年の Google I/O で Kotlin が Android

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

    開発の公式サポート⾔語の1 つになることが発表された • Professional Android developers の 50% 以上が Kotlin を使っている (Google I/O 2019 より)
  4. 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
  5. Android Studio に設定を追加してもらう⽅法 ① • 1. [Tools] - [Kotlin] -

    [Configure Kotlin in Project] • 2. Android with Gradle
  6. • 3. [All modules] または [Single module] を選択して OK をクリックする

    Android Studio に設定を追加してもらう⽅法 ①
  7. Android Studio に設定を追加してもらう⽅法 ② • 2. [All modules] または [All

    modules containing Kotlin files] を選択し て OK をクリックする
  8. Android Library モジュールで Kotlin を使う • build.gradle の設定は Android application

    モジュールと同じ • kotlin-android plugin • kotlin-android-extensions plugin (任意) • kotlin-stdlib-jkd7 • core-ktx (任意)
  9. Library モジュールで Kotlin を使う • Kotlin Library モジュール • New

    Module ウィザードには Java Library しかないので、Java Library を Kotlin Library に変換する
  10. 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
  11. Java と Kotlin の共存 • Java コードと Kotlin コードはプロジェクトで共存できる •

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

    テストコードだけ Kotlin にしてみる • 新規のコードは Kotlin で書く • 既存コードを徐々に Kotlin に変えていく • 既存の Java コードを Kotlin に変換する作業は Kotlin の学習効率がよい (個⼈の感想です)
  13. Java → Kotlin • 1. [Code] - [Convert Java File

    to Kotlin File] で Kotlin に変換する • 2. 変換後のコードを修正する • !! を ?:, ?.let, lateinit, by などへ書き換える • 標準関数や KTX や Kotlin Android Extensions などを使うようにする
  14. Kotlin ファイルに Java コードをコピペ • Java コードを Kotlin ファイルにコピペすると⾃動で Kotlin

    コードに変 換されて貼り付けられる • 設定で Kotlin に変換させないようにすることもできる
  15. [Preference] - [Editor] - [General] - [Smart Keys] Java コード

    を Kotlin ファイルにペーストしたときに Kotlin に変換するかどうか ペースト時に Kotlin に変換するか確認する ダイアログを出すかどうか
  16. Convert Java to Kotlin • 愚直な変換 • !!などが残る • !!

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

    を ?:, ?.let, lateinit, by などへ書き換える • 便利な標準関数などは使われない • Kotlin の標準関数は⼀通りチェックしよう • https://kotlinlang.org/api/latest/jvm/stdlib/index.html kotlin.collections kotlin.text パッケージの関数は チェックしよう
  18. Platform type • 昔の Android Framework コードには @NonNull, @Nullable アノテー

    ションがついていない • null が返る可能性に注意しよう
  19. よくある(?)誤解 • プロジェクトの最初から Kotlin にしないといけない? • → 既存の Java プロジェクトでも

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

    • Java のライブラリは Kotlin から使えない? • → 使えます
  21. Kotlin でアノテーションを使うには • Annotation Processing を使っている Java コードを Kotlin に変換する

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

    とエラーになった、どうすれば? • Kotlin で書くことになった新規コードで Annotation Processing を利⽤ するライブラリを使いたいがどうすれば? kapt を使う https://kotlinlang.org/docs/tutorials/android-frameworks.html
  23. ... apply plugin: 'kotlin-kapt' android { ... } dependencies {

    ... implementation "com.google.dagger:dagger:$dagger_version" kapt "com.google.dagger:dagger-compiler:$dagger_version" } モジュール の build.gradle
  24. ... class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById<TextView>(R.id.textView).text = "Hello, world!" } } MainActivity : findViewById 利⽤
  25. ... 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
  26. 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
  27. 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
  28. View binding • レイアウト XML 内の View にアクセスするための Activity の拡張プロパ

    ティを⽣成する • Container で View をキャッシュする • Container = Kotlin で書かれた Activity, Fragment, View, LayoutContainer を実装したクラス
  29. 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; } ... }
  30. View binding • レイアウト XML 内の View にアクセスするための Activity の拡張プロパ

    ティを⽣成する • Container で View をキャッシュする • Container = Kotlin で書かれた Activity, Fragment, View, LayoutContainer を実装したクラス • LayoutContainer (experimental)
  31. 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 にアクセスできるがキャッシュされない
  32. 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); } }
  33. LayoutContainer あり public interface LayoutContainer { /** Returns the root

    holder view. */ public val containerView: View? }
  34. 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 あり キャッシュされる
  35. 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; } ... }
  36. Parcelable implementations generator • experimental • @Parcelize がついたクラスの Parcelable 実装を⾃動⽣成する

    • primitive types や String, enum , objects などサポートしている型は多 い • サポートしていない型に対しては Custom Parceler で対応できる https://kotlinlang.org/docs/tutorials/android-plugin.html#parcelable-implementations-generator
  37. 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<User> { override fun createFromParcel(parcel: Parcel): User = parcel.run { User(readString()!!, readInt()) } override fun newArray(size: Int): Array<User?> = arrayOfNulls(size) } } ⾃前で実装した場合
  38. @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()); } } }
  39. KTX

  40. Android KTX とは • Android Jetpack • Android Framework や

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

    androidx.core:core-ktx:$version sharedPreferences .edit() .putBoolean("key", value) .apply() sharedPreferences.edit { putBoolean("key", value) }
  42. activity-ktx • ComponentActivity に対する extensions 集 • androidx.activity:activity-ktx:$version class MainActivity

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

    : Fragment() { private val viewModel: MainViewModel by viewModels() private val viewModel2: MainViewModel by activityViewModels() ... }
  44. livedata-ktx • Android Architecture Components の LiveData に対する extensions 集

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

    • androidx.lifecycle:lifecycle-viewmodel-ktx:$version class MainViewModel : ViewModel() { fun load() { viewModelScope.launch { ... } } }
  46. KTX の extensions を調べる • Reference ドキュメントの パッケージ Overview の

    「Extension functions summary」「Extension functions」を⾒る
  47. Kotlin plugin channel • [Tools] - [Kotlin] - [Configure Kotlin

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

    Plugin Updates] または [Preferences] - [Languages & Frameworks] - [Kotlin]
  49. Kotlin REPL • [Tools] - [Kotlin] - [Kotlin REPL] •

    対話モードで Kotlin コードを実⾏できる
  50. Show Kotlin Bytecode • [Tools] - [Kotlin] - [Show Kotlin

    Bytecode] • Kotlin Bytecode がみれる
  51. Inspections • [Preferences] - [Editor] - [Inspections] • [Analyze] -

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

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

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

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

    ⽂字列を別の⾔語と認識 して編集できる機能
  56. // 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]+")
  57. // 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]+")
  58. まとめ • 新規プロジェクトは Kotlin!既存プロジェクトも Kotlin 化を進めたほうが 恩恵を受けられる • Kotlin first

    な Android の取り組みが増えてきている(nullability annotation, KTX, Jetpack Compose) • Java と Kotlin のコードはプロジェクトで共存できる • Kotlin は Java と interoperability があるから安⼼して Kotlin を始めよう