Android Weekly #532 まとめ

# 概要

今週のAndroidWeeklyという週報に紹介されている記事のまとめ。
https://androidweekly.net/issues/issue-532
皆さんの最新技術キャッチアップの助けに少しでもなれば幸いです。

## Domain-Specific Models

API通信におけるデータクラスをDomain-Specificに分けることを奨励した記事。

```kotlin
@DatabaseTable(tableName = "boards")
data class Board(
    @DatabaseField(columnName = “name”)
    @SerializedName("BoardName")
    private var boardName: String?,

    private var cards: List<Card>?,

    private var lastViewedTime: Long?
)
```

このように一つのクラスを

- APIとの通信
- Local DBとのやりとり
- UIからのリクエスト

で使いまわしているとデータの`mutability/immutability`や`null/non-null`がごっちゃになって使いづらい。

そこで以下の3つのクラスに分けることを奨励している。

**ApiModels** : API構造に合わせたモデル。immutable & nullable

**DbModels** :  DB構造に合わせたモデル。mutable(これはDBの種類による) & non-null

**UiModels** : UIの要求に合わせたモデル。immutable & non-null

https://blog.danlew.net/2022/08/15/domain-specific-models/





## How to fix common Android API deprecations

新しいAndroidADKリリースの際に発生するメジャーなdeprecationの対策を紹介

#### FragmentでのMenu API

ActionBarにメニューを追加する方法のアップグレード

Before

```kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    ...
    setHasOptionsMenu(true)
} 
```

After

```kotlin
class MyFragment : Fragment(), MenuProvider {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        val menuHost: MenuHost = requireActivity() as MenuHost
        menuHost.addMenuProvider(
            this, viewLifecycleOwner, State.RESUMED
        )
    }
}

// あとはMenuProvider interfaceに必要なmethodをoverrideするだけ
```

#### Handler constructor

`processMessage & Runnable object`をAndroidに送るためのHandlerの使い方のアップグレード

Before

```kotlin
private val handler = Handler()
```

After

```kotlin
private val handler = Handler(Looper.getMainLooper())
```

#### startActivityForResult APIs

`startActivityForResult`はほかのActivityを起動し、`result`を取得するメソッドで写真を撮ったりパーミッションを取得する際に使われる。

Before

```kotlin
startActivityForResult(
    Intents.editProfile(activity, false, null, memberId),
    EDIT_PROFILE
)

// ここで結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == EDIT_PROFILE && resultCode == RESULT_OK) {
        onRefresh()
    }
}
```

After

```kotlin
// このようにlauncherを使うスタイルが奨励されている
private val editProfileLauncher = registerForActivityResult(StartActivityForResult()) { 
    result: ActivityResult ->
    if (result.resultCode == RESULT_OK) {
        onRefresh()
    }
}

editProfileLauncher.launch(Intents.editProfile(activity, false, null, memberId))
```

https://adavis.info/2022/08/how-to-fix-common-android-api-deprecations.html?utm_source=rss&utm_medium=rss&utm_campaign=how-to-fix-common-android-api-deprecations



## Sparking Jetpack Compose at Tinder

TinderがどのようにComposeをアプリへ導入したかについての記事。

まずcomposeがalphaの段階では以下のようなものを作ったりし、チームでcomposeの知見を深めていったそうです。

![0ECej87hPFC74RBon.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696934/0aba99f6-e7cd-2248-a02a-824bea689772.gif)


そしてKotlin, Android Studio, Android Gradle Plugin, AndroidXなどのbuildシステムを調査しまずはユーザーの目に留まりにくい画面に実装することで安定性を調査しました。

その後MaterialThemeの調査を経てComposeをメインとする開発にシフトしていきました。従来のAndroid Viewと比べてコードの再利用性が決め手の一つになったようです。

https://medium.com/tinder/sparking-jetpack-compose-at-tinder-8f15d77eb4da



## Testing Room database with Coroutines and Flows - Testing Fundamentals

Flowを使ったRoom databaseをテストする方法を紹介した記事。ポイントとしては

- Flowをテストするために`Turbine`を使う
- @RunWithでJUnitの代わりにAndroidJUnit4を使う
- `Room.inMemoryDatabaseBuilder`で仮想のデータベースを作る
- test coroutine内でテストを行うために`runTest{}`内でテストを行う

などです

https://blog.devgenius.io/testing-room-database-with-coroutines-and-flows-testing-fundamentals-iii-5f6c3b9e4c94



## Custom Layouts, measuring policies, and BoxWithConstraints in Jetpack Compose

全てのCompose(Box, Column, Row...)の元となる`Layout`を使って自由にComposeを作るやり方を紹介している記事。

Constraint(制約)を親から子に渡していくことでUIを作っていくようです。ここら辺を使いこなせると自由にComposeが作れそう。

https://effectiveandroid.substack.com/p/custom-layouts-measuring-policies





## **Object-oriented or functional? Two ways to see the world**

OOP(オブジェクト指向)、FP(関数型プログラム)の違いについて触れている記事。まず

- OOPは世界をobjectの集まりとみる考え方
- FPは世界をactionの集まりとみる考え方

というのが筆者の主張。例えばベッドルームに関して、OOPではベッド、ランプ...がある部屋みたいになるけどFPだと寝る、くつろぐ、洗濯物をかけるなどができるという表現をする。

コードの例としてはこんな感じ

```kotlin
// OOP
class Paybill(
   //...
) {
   fun pay(): PayedPaybill = …
   
   //...
}

// FP
fun bestStudents(semester: String) = repo
    .findStudentsInSemestet(semester)
    .map(Student::id)
    .map(repo::findUser)
    .filter(::isPassing)
    .sortedByDescending(Student::result)
```



多くの人がOOPを使ってコードを書いていると思っているが実際はかなり入り混じったものを書いている。

例として`Interface`がある

```kotlin
interface UserRepository {
   fun findUser(userId: Int): User
   fun addUser(user: User)
   fun deleteUser(userId: Int)
}
```

これはよく見る実装だが、上で述べたようにactionの集まりを定義している、つまり考え方としてはとてもFPに近いもの。

最後にまとめとしてそれぞれの考え方の利点を述べている

OOP

- XMLやComposeなどのUIの定義
- データベース
- ネットワーク接続

FP

- Rxなどで使われている複雑なtransformation
- ビジネスロジックの実装

まとめとしては以上。オブジェクト指向の本をよく見かけるけど関数型思考に関する本を読むことも読んだほうがいいのかもと思いました。

https://kt.academy/article/oop-vs-fp





## To Flow or not to Flow? Message subscription in Kotlin

CallbackとKotlin Flowをメッセージサブスクリプションを例として説明している記事。

まずCallbackを使う場合はこんな感じ

```kotlin
fun MyStructure.onChange(block: MyStructure.(Key) -> Unit)

myStructure.onChange{ key ->
  println(get(key))
}
```

Flowの場合はこんな感じで、scopeについて考えたり少し手間

```kotlin
val MyStructure.changes: Flow<Key>

myStructure.changes.onEach{ key ->
  println(myStructure.get(key)
}.launchIn(scope)
```

ただsubscribeを解除する場合Callbackは

```kotlin
// Callback
fun MyStructure.onChange(owner: Any, block: MyStructure.(Key) -> Unit)
fun MyStructure.removeChangeListener(owner: Any)
```

このようになり、手動で解除しなければいけないがFlowは自動で管理されるので気にしなくていい。

https://dev.to/altavir/to-flow-or-not-to-flow-message-subscription-in-kotlin-57ea





## Unpacking Android Security: Part 3 — Insecure Communication

モバイルデバイスへのセキュリティ脅威TOP10に関する記事のPart3、今回は第三位の安全でないコミュニケーションについて書いている。

まとめとして

- 必ず通信ではHTTPSを使う
- ユーザー証明書を盲目的に信用してはならない
- 現在特定のサーバーとの通信を保証するためにCertificate pinningという技術が使われているが、CT(ceretificate transparency)という証明書のパブリックキーを使わない技術を導入したほうが安全
- プロダクションアプリでは必ずログを消そう
- 最後に通信を行うコードに関して自分で考えてみる





## MVI with state-machine. Basics.

MVI アーキテクチャパターンについての記事。まずMVIとは

- Model : データを保持し、変更をViewに伝える
- View : UI eventをIntentとしてModelに伝える
- Intent : ユーザーの行動をmodel内でのデータのとして表す

利点としては

- Single source of truth
- 単方向データフロー
- 全体のテストが可能
- JetpackComposeとの親和性

欠点としては

- 簡単なfunctionも冗長になりやすい
- Reducerロジックの多用
- 学習コスト

簡単にまとめると以下の画像にあるStateMachineを使い、状態の変化によってScreenの表示などを変えるよう、個人的にはかなりよさそうなアーキテクチャ
![image-20220903084545373.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696934/00574032-d468-a7c7-4fc8-c03cbec0a99a.png)


https://proandroiddev.com/mvi-architecture-with-a-state-machine-basics-721c5ebed893





## Inspecting Performance

パフォーマンスの監視は三段階に分けられる

- Passive : 単純にLogcatを見たりアプリの速度を目視で確認したりすること
- Manual : Profilerを使いCPU, Memory, Network使用率などを確認
- Automated : Jetpack Macrobenchmark libraryなどを使い自動でアプリ起動などのパフォーマンスを測る

https://medium.com/androiddevelopers/inspecting-performance-95b76477a3d7





## Jetpack Compose Accompanist — An FAQ.

AccompanistというJetpackComposeをサポートするライブラリ群がある。

まず前提としてAndroidXではモジュールを超えてExperimental APIを使うことができない、なので compose の`navigation transition`などを複数モジュールで扱うことができない。

その問題をAccompanistを使うことで解決できる、つまりテスト段階のcompose libraryを自由に使えるようサポートするのが役目。

プロダクションアプリに使うことも可能なようだがバージョン管理には気を付けたほうがよさそう。

https://medium.com/androiddevelopers/jetpack-compose-accompanist-an-faq-b55117b02712





## Droidcon NYC iOS app with Compose

Droidconというイベントの公式アプリでCompose UIを採用した際の話

https://touchlab.co/droidcon-nyc-ios-app-with-compose/