最小限 の Kotlin を最短で学ぶ

最小限 の Kotlin を最短で学ぶ

シンプルな記事あったので。

Learn Kotlin for Android in One Day – Mayur Rokade – Medium

1. 変数

変数は「var」。


var username: String = "some user name"

定数は「val」。Java の final と等価。


val API_DELAY_CONSTANT: Int = 100

null で初期化するには「?」。 null を利用可能にします。


var myString: String? = null

static な定数には「companion object」。


class Animal {

    companion object {
        const val DEFAULT_NUM_OF_EYES = 2
    }
}

animal.numOfEyes = Animal.DEFAULT_NUM_OF_EYES

遅れて初期化するには「lateinit」。


lateinit var user: User
lateinit var items: List<String>

2. 関数

これは、public。Int を返します。


fun getNumber(): Int {
    return 1
}

private で引数を渡す場合。


private fun getStringLength(str1: String, str2: String): Int {
    return str1.length + str2.length
}

static 関数。


class MyStringUtil {

    companion object {
        fun getOddLengthString(str: String): String? {
            if (str.length % 2 == 0) return null

            return str
        }
    }
}
var str: String = MyStringUtil.getOddLengthString("hey")

「?」を使って、null を返すことをコンパイラに伝えています。

3. ループ と when

コレクションである items に「in」で。


var items: List<String> = ArrayList<String>()

for (item in items) {
    // do something with item
}

インデックスにアクセスすることもできる。


for (index in items.indices) {
    // access items using index
    // items.get(index)
}

Java の switch は、Kotlin では「when」。


// A cool example of when statement
fun describe(obj: Any): String? {
    var res: String? = null

    when (obj) {
        1 -> { res = "One" }         // if obj == 1
        "Hello" -> res ="Greeting"  // if obj == "Hello"
        is Long -> "Long"            // if obj is of type Long
        !is String -> "Not string"   // if obj is not of type String
        else -> {
            // execute this block of code
        }
    }

    return res
}

4. Null 安全

Java で NPE を避ける場合。if で。


if (person != null && person.department != null) {
    person.department.head = managersPool.getManager()
}

Kotlin では「?」を使って、if を省くことができる。chain可能。


person?.department?.head = managersPool.getManager()

null の場合を処理したいときは「?:」を使う。


var name = person?.name ?: throw InvalidDataException("Person cannot be null.")

5. クラス

「open」で継承可能。なければ, Java の final class と同じ。


open class Animal {
    // This class is open and
    // can be inherited
}

class Dog : Animal() {  // Notice the paranthesis
    // Class dog is final and
    // can't be inherited
}

// Compiler throws error
class Labrador : Dog {

}

6. シングルトン

「object」を使う。


object Singleton {
    var name: String = "singleton object"

    fun printName() {
        println(name)
    }
}

// later in the code
Singleton.name
Singleton.printName()

7. インターフェース

インターフェースの継承は直感的に。


interface Named {
    fun bar()
}

interface Person : Named { // Person inherits Named
    fun foo()
}

class Employee() : Person {
    override fun bar() {
        // do something
    }

    override fun foo() {
        // do something
    }
}

関数に渡す場合は少し違う。


// A function that accepts and interface as a parameter
private fun setOnClickListener(listener: View.OnClickListener) {
    // do something
}

// Passing an interface to the function
setOnClickListener(object : View.OnClickListener{
    override fun onClick(view: View?) {
        // do something
    }
})

8. 型チェックとキャスト

「is」や「!is」を使う。


if (obj is String) {
    print(obj.length)
}

if (obj !is String) {
    print("Not a String")
}

「as?」を使って例外を避けてキャスト可能。失敗時には null を返す。


val x: String? = y as? String

9. 例外

Java とほぼ同じ。


throw Exception("Hi There!")

try {
    // some code
}
catch (e: SomeException) {
    // handler
}
finally {
    // optional finally block
}

まとめ

重要な最小限の部分からきちんと学んでいくこと大事。

- Kotlin で FizzBuzz
- 「Fragment を利用するか、しないか」という話


【Android Pie】Auto-rotate (自動回転) OFF のときの挙動

「Auto-rotate (自動回転)」 機能は、ON にしてますか?

ONにすると画面を自動回転してくれてます。

画面を縦長で見てるときに、

端末を横向きにすると、自動で回転してくれます。

しかし、寝転んでスマホ画面を見る場合、視線の方向と直角に向いてしまいます。

私たちを見てくれているのではなく、地球に合わせて自動回転していたのです。

また、意図しない回転を始めることが多く、回転終了までにも時間がかかるので、私は、OFF にして縦に固定していました。

しかし、たまに横長の画面で見たくなる場合があります。

そんなときは、以下の手順です。

1. 通知バーから Auto-rotate を ON にする。
2. 端末を横に向ける。
3. 画面が自動回転して横長になる。
4. だが、横長画面にならないアプリもある。
5. Auto-rotate を OFF にする。
6. だが、今度は横長画面で固定されてる。

面倒ですよね。

これを寝転がった状態でやろうとするとかなり辛いものがあります。

このことを解消してくれる機能が、Android Pie にあります。

ナビゲーションバーを Pieスタイルに変更したら試してみましょう。

【Android Pie】ナビゲーションバー の ホームボタン を ピル型 にする方法

端末が回転されたとき、表示しているアプリが回転可能なものであれば、ナビゲーションバーの右側に、「回転しますか?」的に数秒間だけボタンを表示して提案してくれます。


回転するならタップ、しないなら無視で画面はそのままです。

端末を回転させたとき、回転の提案ボタンが表示されるのは、以下の条件が必要なようです。

- アプリが回転可能 (orientation の指定なし)
- 端末設定の Auto-rotate 機能が OFF

まとめ?

「Auto-rotate(自動回転)機能」をONにする場面はどんなとき?

Android 9 Pie 使ってみた
【Android Pie】ナビゲーションバー の ホームボタン を ピル型 にする方法
【Android Pie】Google Digital Wellbeing を使う
【Android Pie】Auto-rotate (自動回転) OFF のときの挙動
【Android Pie】使いやすくなった音量設定
【Android Pie】スクリーンショット取得→編集 は「電源ボタン長押し」から
【Android Pie】「通知」設定のシンプルな考え方
👉【公式 2018-05-07】Android Pie のバージョンシェア がやっと 10%超えている件


「Fragment を利用するか、しないか」という話

How often do you actually use fragments in your job? : androiddev

「どれくらいの頻度でFragmentを使っていますか。」というスレ。

興味深いコメントを多く見ることができます。

以前からFragmentについては否定的な意見を続けている Jake Warthon さんも登場しています。

5 years sober!

5年間使っていない。

Fragments don't represent anything overwhelmingly challenging. Creating re-usable pieces of UI tied to reusable controller/presenter/whatevers doesn't even require a library. Their problem stems from a lifecycle that's too complicated compounded with a menu system that's convoluted and obsolete compounded with trying to solve dialogs, UI, and retaining instances across rotation compounded with asynchronous transactions compounded with an opaque backstack.

Fragment はチャレンジするものではありません。再利用可能なUIのパーツ作成には、再利用可能なコントローラやプレセンターなどを使えば他のライブラリなど必要ありません。問題なのは、複雑すぎるメニューの仕組みとライフサイクルが根源で、不透明なバックスタックを抱えた非同期トランザクションを組み込んでおり、ローテーション時のインスタンス保持をダイアログやUIに対して解決しようとして複雑になりすぎています。

All of these things should have been decoupled: creating modular bits of UI + code with a simple lifecycle, navigation between conceptual destinations, workers that are retained across rotation, and multiple sources of contribution to a menu.

以下のように分離すべきです。

- シンプルなライフサイクルをもつ小分けされた UI+コード
- 概念的な遷移先への遷移
- ローテーション時のワーカーの保持
- メニューに必要な複数のソース

また、「別Activityに遷移する場合は起動に時間がかかる」ということに関しては以下のように答えています。

I only use a single activity. Activity transitions are a mess. I've never seen one that didn't jank or get screwed up by the result of scrolling or adapter changes behind the scenes. I'll use a second activity if there are vastly different window styles such as a pop-up as the result of a notification vs. the full-screen app. Granted, transitions in the same window are also a mess since the use of view overlay means elevation doesn't work... but at least when everything is in one window you actually have control of things.

一つの Activity とします。Activityのトランジションはややこしいです。スクロール処理やアダプターの変更結果で悩まされたり苦労してないものを見たことがありません。

通知の結果としてのポップアップやフルスクリーンのアプリなど、ウィンドウスタイルが大きく異なる場合は、2番目のアクティビティを使用します。 確かに、同じウィンドウ内での遷移は、表示オーバーレイ時にエレベーションが機能しないので混乱しますが、少なくともすべてが1つのウィンドウ内にあるときは、実質的には処理できます。

I've been doing it this way for the last 5 years. No problems. Or rather, all the problems were problems with how the screen was implemented and not with the mechanism itself. The fine grained control shouldn't be at the site requesting navigation anyway. It's either data in the arguments of the navigation action or an implementation of whoever is implementing the mechanism of animation between screens. Neither belongs inside the call site of screen initiating navigation nor the destination screen.

私は、このやり方で5年間やってきましたが何の問題もありません。メカニズム自体が問題になることはなく、むしろ、すべての問題は画面の実装方法によるものです。とにかく、遷移をリクエストする側にきめ細かいコントロール処理を置いてはいけません。遷移のアクションかアニメーションどちらかの利用する引数データだけを置きます。これらは、遷移元、遷移先のどちらにも属しません。

具体的にこんなやりとりもあります。

I'm not sure how he handles viewpager without fragments but for all other purposes he mostly uses custom views (at least that's what I've found from his github)

FragmentなしでViewPagerの使い方がわかりません。他はカスタムViewでやっています。

View pager.

「View」の Pager ですよ。

ネット上にもFragmentを利用したサンプルばかりが目に付きますが、

結局、Fragmentを使う理由は、

「Fragmentを使わない実装方法が分からない、分かりづらい」

というのが実質的なところでしょうか。