Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

#DroidKaigi 既存のAndroidプロジェクトに Kotlinを導入した話

#DroidKaigi 既存のAndroidプロジェクトに Kotlinを導入した話

Jumpei Yamamoto

February 19, 2016
Tweet

More Decks by Jumpei Yamamoto

Other Decks in Programming

Transcript

  1. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > ⾃自⼰己紹介 -

    ⼭山本純平   - Sansan株式会社  Eight事業部     - EightのAndroidアプリの開発   - twitter:  @boohbah   - github:  https://github.com/yamamotoj
  2. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > お話すること Sansan社のEightアプリでの開発事例例を元

    に、Kotlinを既存のJavaのプロジェクトへの 導⼊入する際に学んできたことをお話します。
  3. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > アジェンダ -

    Eightの紹介   - 弊社アプリでのKotlin導⼊入の経緯、実記録   - 使ってよかったところ   - ⼤大変だったこと   - Java環境と上⼿手に共存するためのTips
  4. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 8 2015年年  Google

     Play  Storeの   ベストアプリに選ばれました!   (2年年連続)
  5. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Eight  Androidアプリ

    - 2012年年から継続的に開発   - 2週間  〜~  1ヶ⽉月のスパンで新機能リリース   - 2015年年8⽉月よりKotlin導⼊入   - アプリ内のKotlin⽐比率率率は約15% Files Total  Lines Java 429 68527 Kotlin 140 10687
  6. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 導⼊入のきっかけ -

    前職はiOS開発でSwiftメイン   - そもそもにJavaのコードに不不満   > ボイラープレートが多い   > Null安全でない   > 型推論論されない   > RxJavaとかで無名クラスつらい   - プロジェクトメンバがすでにkotlinを使い始めていた
  7. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 初コミット -

    サンプル実装のプロジェクトで試験導⼊入   -  Java  -‐‑‒>  Kotlinの変換   - 導⼊入時に増加するapkのサイズは823KB(1.0.0現在) public  class  SampleClass  {
        private  String  name;
        public  String  getName(){
                return  name;
        }
 } class  SampleClass  {
        val  name:  String?  =  null
 }  
  8. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 13 9⽉月 10⽉月

    11⽉月 12⽉月 1⽉月 2⽉月 2015年年 2016年年 m13 m14 β1 β2 β3 β4 RC 1.0 • Kotlin初コミット(8/27) • 2回⽬目のコミット  (10/5) • 初めてのActivity  (10/20) • 本格的なKotlin化  (11/M) • 新規コードはすべてKotlin 1ヶ⽉月ほど寝かす ⼿手を付け始めてから軌道に乗るまで  2-‐‑‒  2.5ヶ⽉月
  9. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 導⼊入しはじめのメンバーの反応 -

    はじめはKotlinに及び腰   - ついつい慣れたJavaで書いてしまう   - レビューに時間がかかる はじめは厳しいけど   射撃しつつ前進!!
  10. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 導⼊入の推進⼒力力 -

    個⼈人の興味   > 魅⼒力力に気づくと早い   > m13でsealed  class導⼊入でやる気になった   - レビューによる知識識の共有   > Kotlinの便便利利な機能を知る  -‐‑‒>  さらにKotlinに興味がでてくる   - iOSエンジニアからも受けがよい   > SwiftににているのでiOSエンジニアでもレビューしやすい   > 実装の知⾒見見をAndroid  /  iOSで共有出来る
  11. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > コードレビューが効率率率的 -

    作りこむ機能に対してコード量量が少ない   - ボイラープレートが少ないので、コード上の読むべき箇所 がわかりやすい   - コード上の匂いのする場所が浮き彫りになりやすくなる   > なぜvarを使っているのか?   > Single  expressionで書けないメソッドは?   > !!を使っている箇所
  12. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > バージョンアップに関わる問題 -

    ある程度度メジャーなバージョンアップ直後は問題が起こる ことが多かった   > 0.13.1513  <-‐‑‒  アプリが起動できない重⼤大な問題     > 0.13.1514  <-‐‑‒  直後にマイナーバージョンアップ   - いきなりProguardでエラーが発⽣生
  13. Copyright  ©  Sansan,  Inc.  All  rights  reserved. Kotterknife   Kotlin

      1.0.0  beta1 Kotlin   1.0.0  beta1 > SNAPSHOTバージョン指定の問題 - バージョンにSNAPSHOT 指定されている場合、同じ バージョンでも異異なるライ ブラリがリリース可能。   - 取得する側では常に最新の ライブラリを取得する。 compile  'com.jakewharton:kotterknife:0.1.0-­‐SNAPSHOT' Kotlin   1.0.0  beta2 My   Application   Kotlin   1.0.0  beta1 Kotlin   1.0.0  beta2 ⾃自動的に   ダウンロード Զ͸·ͩ όʔδϣϯΞοϓ ͨ͘͠ͳ͍Μͩʔʂ
  14. Copyright  ©  Sansan,  Inc.  All  rights  reserved. JVM  /  Androidライブラリの特定

    のコミットを取得して、jarをビ ルドして配布してくれるサービス dependencies  {          compile  'com.github.JakeWharton:kotterknife:36ae6d5ecb'   }   allprojects  {       repositories  {         ...         maven  {  url  "https://jitpack.io"  }       }     }
  15. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > kotterknife class

     MainActivity  :  AppCompatActivity()  {          val  textView:  TextView  by  bindView(R.id.textView)          override  fun  onCreate(savedInstanceState:  Bundle?)  {                  super.onCreate(savedInstanceState)                  setContentView(R.layout.activity_main)          }   } Jake  Wharton⽒氏作成のview  injectionライブラリ   Kotlin版  Butter  Knife
  16. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Fragmentでは class

     MyFragment  :  Fragment()  {          val  textView:  TextView  by  bindView(R.id.textView)          override  fun  onCreate(savedInstanceState:  Bundle?)  {                  super.onCreate(savedInstanceState)                  retainInstance  =  true          }          override  fun  onCreateView(                          inflater:  LayoutInflater?,                          container:  ViewGroup?,                          savedInstanceState:  Bundle?):  View?  {                  return  inflater?.inflate(R.layout.fragment_main,  container,  false);          }   }   retainInstance  =  true   にすると画⾯面が回転した時には   Fragmentインスタンスは開放されずに   Viewが再⽣生成される Viewが再⽣生成され ても、再⽣生成前の Viewが残る
  17. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > kapt -

    Kotlin  Annotation  Processing  Tool   - Kotlin上でPluggable  Annotation  Processing  API  (JSR  269)  を 使って実装されたライブラリを使う際に必要となる   - Kotlinのソースに付与されたアノテーションを解釈する   - KotlinからAnnotationで⽣生成されたコードを参照できるようにする   - DataBindingライブラリとの相性が悪く導⼊入できていない   - いまのところAnnotationで⽣生成されたクラスへの参照はJavaから しか参照できない
  18. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Kotlinは100%Java互換 -

    KotlinのコードはすべてJavaから参照することができる。   - JavaのコードもKotlinから参照することができる。   - KotlinのコードをJavaから参照するときに使えるアノテー ション   > @JvnStatic   > @JvmField   > @File:JvmName(“name”)   > @JvmOverrides
  19. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > @JvmField class

     Bar  {          val  name  =  “name”          @JvmField  val  password  =  “password”          companion  object{                val  staticName  =  "name"                  @JvmField  val  staticPassword  =  "password"          }   } //Java   Bar  bar  =  new  Bar();   String  name  =  bar.getName();   String  password  =  bar.password;   String  staticName  =  Bar.Companion.getStaticName()   String  staticPassword  =  Bar.staticPassword
  20. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Parcelable class

     MyParcelable(val  name:  String)  :  Parcelable  {          protected  constructor(src:  Parcel)  :  this(src.readString())          override  fun  describeContents():  Int  =  0          override  fun  writeToParcel(dest:  Parcel,  flags:  Int)  {                  dest.writeString(name)          }          companion  object  {                  val  CREATOR:  Parcelable.Creator<MyParcelable>  =                                  object  :  Parcelable.Creator<MyParcelable>  {                                          override  fun  createFromParcel(`in`:  Parcel):  MyParcelable  {                                                  return  MyParcelable(`in`)                                          }                                          override  fun  newArray(size:  Int):  Array<MyParcelable?>  {                                                  return  arrayOfNulls(size)                                          }                                  }          }   } @JvmField このままだとJavaからは   MyParcelable.Companion.CREATER   と⾒見見えてしまう
  21. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > @file:JvmName() //

     KotlinExtensions.kt   @file:JvmName("StringUtil")
 
 fun  String.prepend(str:String)  =  str  +  this   “Kotlin”.prepend(“Hello!  ”)  //  -­‐>  Hello!  Kotlin //  Java   StringUtil.prepend("Kotlin",  "Hello!  “);   //  >  Hello!  Kotlin
  22. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Null  safety

    val  nullable:  String?  =  null  //  NullΛ୅ೖ͢Δ͜ͱ͕ Ͱ͖Δ   val  nonNull:  String  =  “string”  //  NullΛ୅ೖͰ͖ͳ͍   val  nonNull:  String  =  null  //  ίϯύΠϧΤϥʔ notNullなパラメータにnullを代⼊入しようとすると   コンパイルエラー
  23. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Kotlin関連のcrash原因トップ Parameter

     specified  as  non-‐‑‒null  is  null;   non-‐‑‒nullで指定された変数がnull
  24. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 実はJavaから渡された変数 //

     Java   public  class  Hoge  {          public  String  getString()  {                  return  null;          }   } String!は   StringとしてもString?としても参照できる
  25. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > @Nullable  /

     @NotNull  アノテーション //  Kotlin   val  hoge  =  Hoge()   val  s0:String?  =  hoge.nullable   val  s2:String  =  hoge.nullable //  Java   public  class  Hoge  {          @NonNull          public  String  getString()  {                  return  "hoge";          }          @Nullable          public  String  getNullable()  {                  return  null;          }   }   @Nullableアノテーションをつける ことでKotlinからNonNullなプロパ ティで受けようとするとコンパイ ルエラー
  26. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > ただし Javaでは@NonNullアノテーションをつけたプロパティがnullを返して

    も、静的チェックに引っかかるだけで、エラーにはならないので注意。 //  Java   public  class  Hoge  {          @NonNull          public  String  getString()  {                  return  null;          }   }
  27. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > まとめ -

    祝Kotlin  1.0.0!   - ⼤大変だったことのほとんどはバージョンアップに伴う問題 だった。   - 今Javaのプロジェクトをやっている⼈人でも安⼼心してKotlin を導⼊入できる