Kotlin を使用した Android アプリの開発(Developing Android Apps with Kotlin)

5月 27, 2020

この記事で解決すること

Android 開発の公式の学習教材である 「Kotlin を使用した Android アプリの開発(Developing Android Apps with Kotlin)」をスムーズに学習できます。

この記事の想定読者

  • Android アプリの開発(Developing Android Apps with Kotlin)を学習する方
  • Kotlin による開発を始めたばかりの方

この記事で分かること

  • Android の最新開発環境とレッスン作成当時の開発環境の違いによって起きる問題が回避できます。
  • レッスンのポイントを押さえられます。

目次

開発環境

このレッスンを受講している時の開発環境です。

教材の開発環境

Android Studio 3.3

Android SDK Build-Tools 28.0.3

教材プロジェクトのビルド設定サンプル

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.android.dessertpusher"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    dataBinding {
        enabled = true
    }
}

受講に使用した開発環境

私は都合により、Windows と Mac の両方で開発していますが、どちらか一方で構いません。

Windows

Android Studio 3.6.3

SDK Platforms Android 10.0 (Q)

Android SDK Build-Tools 29.0.3

Mac

Android Studio 3.6.3

SDK Platforms Android 8.1 (Oreo)

Android SDK Build-Tools 27.0.3

Android Gradle Plugin の更新はしない

Android Studio の右下に、Gradle Plugin の更新を促すポップアップが表示されますが、更新は不要です。

公式サイトでも、ビルドが正常に行われなくなる可能性があるため、更新しなくて良いと記載されています。

Kotlin を使用した Android アプリの開発

Developing Android Apps with Kotlin

レッスン1 最初のアプリを作成する

Build your First App

開発環境のセットアップから始めて、基本的な事を学びながら簡単なアプリを作成します。

注意点

ImageView クラスは、2つあります。
android.widget.ImageView
android.media.ImageView

このレッスンで使用するものは、android.widget.ImageView の方です。

クイズの回答方法

途中で出題されるクイズの回答方法についてです。

青色の回答候補をドラッグして、下の回答欄にドロップします。

全て回答し終えたら submit ボタンを押下し、採点されます。

間違えていても次の教材には進めます。

サンプルプログラムの入手

各レッスンで使用されるサンプルプログラムは、GitHubで公開されています。

レッスンの途中で、サンプルプログラムのリンクが記載されています。

zipファイルも公開されていますが、git clone することをお勧めします。

git リポジトリでは、レッスン途中の状態がブランチ作成されており、ブランチ「Step…-Excercise…」はその課題の対応前、ブランチ「Step…-Solution…」はその課題の対応後のソースコードになっています。

課題対応前に、ブランチ「Step…-Excercise…」を checkout し、TODO 箇所を講義に沿ってコーディングすることで、実際にコードを作成しながら学習できます。

答え合わせは、git diff でブランチ比較を使用することで容易に行えます。

実機での確認

Android 端末で開発者向けオプションを有効にし、PCとUSB接続し実行すると、インストールされ確認できます。

  1. 開発者向けオプションの有効化
    1. 設定 ⇒ バージョン情報 ⇒ ソフトウェア情報 ⇒ その他 ⇒ ビルド番号 を7回タップする(HTC U11)。
    2. 端末によって、ビルド番号までのメニュ選択は異なります。
  2. 開発者向けオプションで、USB デバッグをオンにする
  3. PC と端末をUSB接続する
  4. Android Studio で実行ボタンを押すと、アプリがインストールされます

参考:Android アプリを実機でテストする方法(1) 実機の設定

レッスン2 レイアウト

Layouts

UI レイアウトの基本について学びます。

特に ContraintLayout について理解することが、様々なデバイスや状態で適切な UI を提供する上で重要です。

注意点

レッスンで示されているレイアウト方法が、最新のレイアウト・エディタでは異なっている場合があります。

ここでは細かい点は気にせずに、おおよそ出来ていればそのまま進めることをお勧めします。

完全にサンプルと同じ手順で進めることは、古い手法なのかもしれません。

レッスン3 アプリのナビゲーション

App Navigation

ナビゲーションを使って、複数の画面へ移動することを学びます。

サンプルプログラム

それなりのプログラム作成を行いますので、アプリらしさが分かってきます。

レッスン4 アクティビティとフラグメントのライフサイクル

Activity & Fragment Lifecycle

アプリのライフサイクルについて学べます。

この基本を押さえて対応することで、ユーザの期待に沿った動き(前の画面に適切に戻るなど)ができるようになります。

ログ出力

このレッスンのサンプルでは、ライフサイクルを正確に確認するために、Callback 関数で timber を使用してログ出力しています。

ADB の実行

途中に、ADB (Android Debug Bridge) を使用して、プロセスを終了した際の挙動を確かめる講義があります。

普通の方の環境では、adb コマンドラインツールは動作しないと思いますので、記載内容に従って、各自環境で adb へのパスを設定すれば動作します。

アクティビティのライフサイクル

このレッスンで、何度も出てくる図です。この状態遷移を正確に把握する必要があると言っています。

一般的な定義

Visible Lifecycle: アクティビティが表示されているときの onStart とonStop の間のライフサイクルの部分。

Focus: アクティビティは、ユーザーが操作できるアクティビティである場合にフォーカスがあると言われます。

Foreground: アクティビティが画面上にあるとき。

Background: アクティビティが完全に画面外にある場合、それはバックグラウンドであると見なされます。

ライフサイクルの状態

これらは、フラグメントライフサイクルとアクティビティライフサイクルの両方で同じです。

Initialized: これは、新しいアクティビティを作成するときの開始状態です。これは一時的な状態です-すぐにCreatedになります。

Created:アクティビティは作成されたばかりですが、表示されず、フォーカスもありません(操作できません)。

Started: アクティビティは表示されていますが、フォーカスがありません。

Resumed: 実行中のアクティビティの状態。それは目に見え、焦点があります。

Destroyed: アクティビティは破棄されています。いつでもメモリから排出される可能性があるため、参照したり操作したりしないでください。

レッスン5 アプリアーキテクチャ(UIレイヤー)

App Architecture (UI Layer)

UI レイヤーのプログラム開発において、既に用意されているアーキテクチャコンポーネントを使用して開発する方法が学べます。

ViewModel を使った、MVVM(Model-View-ViewModel)について、詳しく解説されています。

かなり重厚なレッスンですので、焦らずに進めましょう。

Android アーキテクチャ

このレッスンでは、Android のアーキテクチャについて、多くの情報が紹介されています。

Android Architecture Blueprints v2 が、比較的新しい情報があるようです。

注意点

すべてのコードを1つの Activity や Fragment に記載するのでなく、これらは UI や OS とのやり取りのみに限定して、クラスをシンプルに保つことが、関心の分離として推奨されています。

ただし、この記事では、ViewModel と onSaveInstanceState の組み合わせになっていますが、2019年5月の時点では ViewModel と SavedStateHandle で実装するように改善されているようです。

注意点

課題のStep.11 では、ゲームの残り10秒を着ると、スマホを振動させる動きをさせます。

ただし、エミュレータでは振動しないようなので、振動させるAPIを呼び出しているか Log で確認すると良いです。

GameFragment.kt で、下記 Log をコーディングすると、"buzzer 1″ が Logcat に表示されます。

   private fun buzz(pattern: LongArray) {
        val buzzer = activity?.getSystemService<Vibrator>()
        buzzer?.let {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                buzzer.vibrate(VibrationEffect.createWaveform(pattern, -1))
                Log.i("GameFragment", "buzzer 1")
            } else {
                //deprecated in API 26
                buzzer.vibrate(pattern, -1)
                Log.i("GameFragment", "buzzer 2")
            }
        }
    }

レッスン6 アプリアーキテクチャ(永続性)

App Architecture (Persistence)

データベース(SQLite)への基本的なデータ格納方法が学べます。

RoomDatabase

この教材では、android.arch.persistence.room.RoomDatabase を使用しているが、現在は androidx.room.RoomDatabase が推奨されています。

現時点では、旧クラスでもビルドは可能であり、教材は進められます。

Unit Test

Unit Test が初めて出てきます。Unit Test については、このレッスンだけでは不足する内容ですので、別途学習することをお勧めします。

Android でアプリをテストする
Robolectricは、Androidに高速で信頼性の高い単体テストを提供するフレームワークです。

Coroutines

Coroutins (コルーチン)は、コールバックの必要性を減らすことでコードを簡略化できるバックグラウンドスレッドを管理する新しい方法です。Coroutines は、データベースやネットワークアクセスなどの実行時間の長いタスクの非同期コールバックを順次コードに変換する Kotlin の機能です。

概観 コルーチン
言語ガイド コルーチン
Android アプリで Kotlin コルーチンを使用する (Codelabs)

レッスン7 RecyclerView

RecyclerView

大量の要素で、効率的に表示や更新が行える RecycleView を学びます。

サンプルアプリは、レッスン6の Sleep Tracker をベースに、RecycleView を適用して行きます。

教材誤り(8.Exercise: Display the SleepQuality List)

教材に誤りがありますので、気をつけましょう

「3. Add a TextView to the right of quality_image and set its id to sleep_length:」 ⇒ quality_string

「4. 」 R.layout.text_item_view  ⇒ R.layout.list_item_sleep_night

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        val view = layoutInflater.inflate(R.layout.list_item_sleep_night, parent, false)
        return ViewHolder(view)
    }
教材誤り(23. Extra Credit: Add a List Header)

教材に誤りがありますので、気をつけましょう

holder.bind(nightItem.sleepNight, clickListener) ⇒ holder.bind(clickListener, nightItem.sleepNight)

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (holder) {
            is ViewHolder -> {
                val nightItem = getItem(position) as DataItem.SleepNightItem
                holder.bind(clickListener, nightItem.sleepNight)
            }
        }
    }

adapterScope.launch と list.map の {} の位置は、下記コードが正解です

    fun addHeaderAndSubmitList(list: List<SleepNight>?) {
        adapterScope.launch {
            val items = when (list) {
                null -> listOf(DataItem.Header)
                else -> listOf(DataItem.Header) + list.map { DataItem.SleepNightItem(it) }
            }
            withContext(Dispatchers.Main) {
                submitList(items)
            }
        }
    }

レッスン8 インターネットに接続する

Connect to the Internet

Retrofit (A type-safe HTTP client for Android and Java) を使用して、インタネットからデータを取得して表示することを学びます。

画像の表示には、Gllide (Glide is a fast and efficient image loading library for Android focused on smooth scrolling) を使用します。

このレッスンでは、下図のアプリケーションを作ります。

火星の画像が約800枚用意されていますが、RecyclerView で実装することで、サクサクスクロールします。

火星の土地の価格

なぜか販売価格より賃貸価格の方が安いです。多分、データのステータスが間違っています。
どちらにしろ、仮定の話ですが…。
プログラムが間違っているのではないかと、ハマらないで下さい。

Android パーミッションを扱うときの原則

Android パーミッションを扱う際は、次の原則に従うことが推奨されています

※このレッスンでは、インターネット接続のためにアプリに権限をつけます。

1: アプリの動作に必要なパーミッションだけを使用する。パーミッションの使用方法によっては、機密情報にアクセスすることなく、別の方法(システム インテント、識別子、通話時のバックグラウンド移行)で必要な処理を実行できる場合があります。

2: ライブラリが必要とするパーミッションに注意する。 ライブラリを追加すると、パーミッション要件も継承します。追加する要素、その要素が必要とするパーミッション、そのパーミッションの用途について注意する必要があります。

3: 透明性を確保する。 パーミッションをリクエストするときは、アクセス対象とアクセス理由を明確にし、ユーザーが十分な情報に基づいて判断できるようにする必要があります。インストール時や実行時、パーミッション更新時のダイアログなど、パーミッションのリクエストとともにこの情報を表示してください。

4: システム アクセスを明示的にする。 機密性の高い機能(カメラ、マイクなど)にアクセスするときは、継続的に通知を表示することで、データ収集のタイミングをユーザーに明確に示し、データをひそかに収集しているという疑いをもたれないようにします。

レッスン9 舞台裏

Behind the Scenes

後日更新します。

レッスン10 みんなのためのデザイン

Designing for Everyone

後日更新します。

問題と解決策

教材に合う SDK Build-Tools に更新する

最新の Android Studio を使って、このレッスンのサンプルプログラムをビルドすると、SDK Build-Tools 28.0.3 が見つからないエラーが出ると思います。

license for package android sdk build-tools" 28.0.3 "not accepted.

Android Studio 下部のウィンドウに、見つからない sdk build-tools をインストールするリンクが出ますので、クリックしてインストールするとビルドが可能となります。

Android エミュレータ が起動しない時

Macで AVD Pixel_2_API_28 が起動しない事がおきました。

ADK Manager で、AVD の Cold Boot Now を選択すると、起動することが出来きました。その後のデバッグでも使用可能でした

ビルドエラーの文字化けを解消

ビルドエラーの文字列が文字化けする時は、カスタム VM オプションに設定を加えることで解消できます。

Android Studio ⇒ ヘルプ(H) ⇒ カスタム VM オプションの編集…

-Dfile.encoding=UTF-8

設定終了後に、Android Studio を再起動します。

参考:Android StudioにおけるBuild Outputの文字化けを解消