Android
Kotlin

Convert Java to Kotlin

既存のJavaで書かれたAndroidアプリをKotlinへ移行中に
気づいたことをまとめていきます。随時追記します。

Code変換

AndroidStudioのメニュー、Code → Convert Java File to Kotlin File
で、Javaファイルがktファイルに変換されます。
↓のメッセージが表示されるかも。

some code in the rest of your project may 
require corrections after performing this conversion. 
do you want to find such code and correct it too ?
プロジェクトの残りの一部のコードでは、
この変換を実行した後に修正が必要な場合があります。
あなたはそのようなコードを見つけてそれを修正したいでしょうか?

Yes!!

CustomView

例としてスクロールしないListViewなCustomViewを。
@JvmOverloads とか使うこと。
コンストラクタ沢山書かなくていいからいいですね。

java
class NonScrollListView : ListView {

    constructor(context: Context) : super(context) {}
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}

    public override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val heightMeasureSpec_custom = View.MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE shr 2, View.MeasureSpec.AT_MOST)
        super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom)
        val params = layoutParams
        params.height = measuredHeight
    }
}

kotlin
class NonScrollListView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ListView(context, attrs, defStyleAttr) {

    // イニシャライザ(インスタンス生成時の初期処理はここで)
    init {
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val heightMeasureSpec_custom = View.MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE shr 2, View.MeasureSpec.AT_MOST)
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val params = layoutParams
        params.height = measuredHeight
    }
}

null許容

non-null型なのにnullが入るとこの例外です。

error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull

メッセージに続けて変数名とかヒントがあると思うので
?を付けてnull型に

Data Binding

Kotlin用のData Bindingの準備としてGradleに追記します。
追記したあとはCleanだったりAndroidStudioの再起動が必要かも。
レイアウトファイル側はJava時代から変更はありません。そのままでOK

プロジェクトのGradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = '1.1.60'
    ext.android_plugin_version = '2.3.3'
Gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

...

dependencies {
    ...
    // Kotlin
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    kapt "com.android.databinding:compiler:$android_plugin_version"
}    

Retrofit用データクラス

Listがネストするような場合、Collectionにしたらうまくいった。

java
class Data {
    public List<List<Hoge>> hoge = new ArrayList<>();
}
kotlin
class Data {
    var hoge: Collection<Collection<Hoge>> = ArrayList()
}

LinkedHashMapのキーから値を取得

文字列をキーに数値を持つLinkedHashMapがあったとして
↓のようにキーから値を取得していたコードは

java
    mapHoge["hoge"]

そのままだと↓でエラーなので、値が取得できないケースもデフォルト値でフォローする

error
Type mismatch.
Required: Int
Found: Int?
kotlin
    mapHoge.getOrDefault("hoge", 123)

継承

kotlin
// openを付けないと継承できない
open class Base {
}

class Hoge : Base() {
}