Kotlin 1.3 で CoroutineScope

Kotlin 1.3 RC is Here: Migrate Your Coroutines! | Kotlin Blog

新しくこんなの出てます。


public interface CoroutineScope {

  /**
   * Returns `true` when this coroutine is still active (has not completed and was not cancelled yet).
   *
   * Check this property in long-running computation loops to support cancellation:
   * ```
   * while (isActive) {
   *   // do some computation
   * }
   * ```
   *
   * This property is a shortcut for `coroutineContext.isActive` in the scope when
   * [CoroutineScope] is available.
   * See [coroutineContext][kotlin.coroutines.experimental.coroutineContext],
   * [isActive][kotlinx.coroutines.experimental.isActive] and [Job.isActive].
   *
   * @suppress **Deprecated**: Deprecated in favor of top-level extension property
   */
  @Deprecated(level = DeprecationLevel.HIDDEN, message = "Deprecated in favor of top-level extension property")
  public val isActive: Boolean
    get() = coroutineContext[Job]?.isActive ?: true

  /**
   * Returns the context of this scope.
   */
  public val coroutineContext: CoroutineContext

}

新しいコルーチンのスコープです。

すべてのコルーチンビルダーは CoroutineScope の拡張となり、これを継承したコルーチンコンテキストは自動的にすべての要素にキャンセルを伝えることができます。

これを使って、アクティビティのライフサイクル周りを実装します。


class MyActivity : AppCompatActivity(), CoroutineScope {

  lateinit var job: Job

  override val coroutineContext: CoroutineContext
      get() = Dispatchers.Main + job


  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    job = Job()
  }


  override fun onDestroy() {
    super.onDestroy()

    // すべての子ジョブが destroy されたあと
    // 自動的にキャンセル
    job.cancel() 
  }


  // Activity が destroy されるか、このメソッド内で、例外が
  // 発生すると、すべてのネストしたコルーチンはキャンセルされる

  fun loadDataFromUI() = launch { // メインスレッドで起動

    val ioData = async(Dispatchers.IO) { // IOコンテキストで起動
      // ブロッキング I/O 処理
    }

    //  I/O の結果を wait
    val data = ioData.await()

    // メインスレッドで描画
    draw(data) 
  }
}

簡単な記述で、ネストしたコルーチンすべてを自動的にキャンセルしてくれるのです。

Kotlin 1.3 RC is Here: Migrate Your Coroutines! | Kotlin Blog

Using Kotlin Coroutines in your Android App


11月1日に迫った「targetSdkVersion は 26以上」に向けての対応の目処

メール来てますよね。

Hello Google Play Developer,

This is a reminder that starting November 1, 2018, updates to apps and games on Google Play will be required to target Android Oreo (API level 26) or higher. After this date, the Play Console will prevent you from submitting new APKs with a targetSdkVersion less than 26.

Configuring your app to target a recent API level ensures that users benefit from significant security and performance improvements, while still allowing your app to run on older Android versions (down to the minSdkVersion).

Action required

Please ensure that your apps are configured to target at least Android 8.0 (API level 26) by November 1, 2018. For technical advice on how to change your app's target API level to meet these requirements, refer to the migration guide.

Affected apps

The apps included below have one or more APKs—in production or testing tracks—that aren't currently targeting API level 26 or higher. Apps are listed with the maximum version code and corresponding targetSdkVersion. If you have more than 20 apps that could be affected in your account, please check the Play Console for a full list.

動くとはいうものの、GoogleサービスAPIの仕様や各サービス/プラットフォームのポリシーの変更が頻繁なことを考えると、放置しているアプリは一掃されていくと思われます。

メールには、以下が「マイグレーションガイド」として案内されています。

Meet Google Play's target API level requirement  |  Android Developers

おおまかに、影響しそうなキーワードを拾っておきます。

API 23 (6.0) 未満

「Runtime Permission」
実行時のパーミッション リクエスト  |  Android Developers

API 24 (7.0) 未満

「Doze」
Doze と App Standby 用に最適化する  |  Android Developers

「Firebase Cloud Messaging (FCM)」
Firebase Cloud Messaging  |  Firebase

「file://」
Setting up file sharing  |  Android Developers

API 26 (8.0) 未満

「startService()」
「startForeground()」
「startForegroundService()」
「Firebase Cloud Messaging (FCM)」
「Google Play services SDK」
「JobScheduler」

バックグラウンド実行制限  |  Android Developers

「Notification」
Create and Manage Notification Channels  |  Android Developers

「ANDROID_ID」
Settings.Secure  |  Android Developers

「multiple window/display」
マルチ ウィンドウのサポート  |  Android Developers
Android 8.0 の機能と API  |  Android Developers

「Camera API」
android.hardware.camera2  |  Android Developers

まとめ

Gradle周りやライブラリ同士の依存関係などもあって簡単には終われないですよね。

保守的に古いSDKにスティックしていた開発陣はモヤモヤ一掃のチャンスと思うべし。

あと、オプトインしといたほうがいいよ、と以下リンクがありました。

http://g.co/play/monthlynews


Androidアプリのアニメーションは必要?

なんとなくスマホイライラの原因の一つではないか、と思う。

More users like to turn off animations than you think.
予想以上にアニメーションOFFは好かれている。

Is it reasonable to assume your app's users have their developer options turned off? : androiddev

そんなあなたはOFFにしましょう。

スッキリしてサクサクします。

「開発者向けオプション(デベロッパーモード)」の有効化が必要ですが、開発者でない人も便利に利用できます。

android デベロッパーモード - Google 検索

有効化したら、その中で3つのアニメーションをOFFにするだけです。

ね、スッキリするでしょう?

どうせ待つなら滑らかアニメーションがあったほうがいいか。


最小限 の 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%超えている件