ぺんぎんメモ

プログラミングのメモです。たまに私生活のことや鬱っぽいことを書きます。

2021年09月01日 Android と Kotlin

今日は1,170円だった。
食べ過ぎたので少し苦しい…。

今日からタイトルを少し変えることにした。
月と日は2桁になるように0埋めし、簡単なタイトルを付ける。
こうすることで、後から見返したときに内容がすぐに分かる。

今日は Kotlin を少し動かし、Android のドキュメントをガッツリと読んだ。
そこで気付いたことがあるんだけど、とあるアクティビティで Firebase Authentication の認証に通ったとき、その後に同じアプリ内の別のアクティビティに遷移してもログイン状態が保たれる。なので、わざわざ認証状態を自分で持つ必要がない。
これは嬉しい。
これで認証周りの不安はなくなった。

話は変わってコンテンツプロバイダについて。
コンテンツプロバイダを使えば、すべてのアプリから一箇所のデータにアクセスできる。
これはつまり、複数のフロントエンドから一つのデータベースにアクセスしているようなもの。
用意されているインタフェースも ORM に似ている。

class MyProvider : ContentProvider() {
  override fun onCreate(...
  override fun query(...
  override fun insert(...
  override fun update(...
  override fun delete(...
}

上記のようなメソッドをオーバーライドしてコンテンツプロバイダを自作する。

そういえば、Android では SQLite が普通に使えるのだろうか?
もし普通に使えるとしたら、それはアンインストールされるまで永続化されるのか?
ということで SQLite を試してみる。

applicationContext というのは、現在実行しているアプリケーションの情報が詰め込まれているのかな。

何もインストールすることなく SQLite を利用できた。
コードはこちらのようになった。
まさか何もインストールせずに SQLite が使えるとは思わなかった。

このコードは「アクティビティから直接 SQLite を利用するコード」だけど、アクティビティと SQLite の間にコンテンツプロバイダを挟むことで、SQLite に保持された情報が他のアプリからも参照できるようになる。
まだ具体例は思い浮かばないけれど、いずれは使うことになりそう。

永続化するデータにアクセスするのが自作のアプリだけの場合は「内部ストレージ」を利用すると良さそう(ドキュメントに「内部ストレージ」と明記されていた気がするけれど、本当に合っているかどうかは不明)。
今公式ドキュメントを見たんだけど、SQLite をラップした「Room」というものを使うと良さそう。

Room を使ったコードはこちらのようになった。
エンティティと Data Access Object とデータベースの3つのクラスを作成し、それぞれに適切なアノテーションを付けて読み込むと使えるようになる。

いくつか注意があり、まずこちらの StackOverflowの手順通りに build.gradle を書く必要がある。次に、UI のスレッド上でデータベースを扱おうとするとエラーが発生するので、新たにスレッドを作成してそちらから扱うようにする。

今まで JavaScript のシングルスレッドばかり扱っていたせいで、マルチスレッドプログラミングに対する恐怖感が凄いある。Kotlin にはコルーチンもあるみたいだけど、実際はスレッドかコルーチンのどちらで記述するのが一般的なんだろう?

Kotlin のコルーチンは2018年10月 のバージョン1.3から実装されたため、約3年前ということになる。枯れているかどうか微妙なライン…。実際に使ってみて良さそうなら使う感じでいく。ただ、コルーチンはマルチスレッドではないため、Room を扱うときは結局はエラーが発生しそう。

ktx」という記述をよく見かける。これは何の略なんだろう。
調べてみると、どうやら Kotlin の拡張らしい。今 build.gradle を確認したところ、次のような記述が見つかった。
プロジェクト生成時に標準で ktx が有効になっているみたいだ。

implementation 'androidx.core:core-ktx:1.6.0'

コルーチンを使用するためには build.gradle に次の1行を追加する必要がある。
コルーチンは標準で使えて欲しい気もする…。

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"

コルーチンは次のように記述する。

GlobalScope.launch {
    delay(1000)
    Log.e("tag", "2")
}
Log.e("tag", "1")

コンソールにはまず 1 が出力され、次に 2 が出力される。
先程「コルーチンはマルチスレッドではないので Room 使用時にエラーが発生する」と言ったけれど、実際はそんなことはなかった。正常に処理が終了した。
GlobalScope というのがよくわからない。

次のようなコードを実行したときは a -> b -> c の順に出力される。

GlobalScope.launch {
    Log.e("tag", "a")
    val promise = GlobalScope.async {
        delay(1000)
        "c"
    }
    Log.e("tag", "b")
    Log.e("tag", promise.await())
}

今日はここまで。