Androidで新機能を実装するときに考慮すること

この記事は、[ドワンゴ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/dwango)の10日目の記事です。

ドワンゴでは[N予備校](https://www.nnn.ed.nico/)の開発をしています。

今年に入ってReactでのWebからKotlin言語でのAndroid開発に配属が変わり、N予備校の新機能を実装する中でWebでは意識してこなかった「Android特有の課題」にいくつかぶつかりました。

今後の開発で同じ課題にぶつからないためにも、ここでAndroidで新機能を実装するときに考慮することをまとめます。

（コードを書く前の話が中心なので、多くの部分はiOSにも共通していると思います。）

# 1. API取得失敗時のエラー処理
Webであれば、APIの通信エラーが発生したらブラウザのエラー表示が出て、ブラウザのリロードを実行すれば解決しますが、Androidではそれらを自前で用意しなければいけません。

しかも、Androidの通信環境は不安定になることが多いので、なおさら注意が必要です。

具体的には以下のポイントを考慮します。

### エラー時には何を表示するか
- エラーになったことをToastで一部表示する
- エラーになったことをDialogで表示する
- エラー画面を表示する

N予備校Androidでは例えば以下のように対策しています。

| Toast表示 | Dialog表示 | エラー画面表示 |
|:--:|:--:|:--:|
| プロフィール設定画面 | 教材選択画面 | 授業一覧画面 |
| ![device-2019-12-02-131708.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227196/18faddb1-6335-24e8-de2e-bdfaea94c88d.png) | ![device-2019-12-02-125846.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227196/9cb6e1cb-ceaa-16e3-e776-40ab3f1da400.png) | ![device-2019-12-02-125750.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227196/248257ab-ad8d-02a2-c51d-92ef2b0df86c.png) |

大きく分類すると、画面遷移する前のエラーに対してはToast（一部Snackbarに移行）でエラー内容を表示、画面遷移した後のエラーに対してはDialogやエラー画面でエラー内容を表示しています。

どちらのパターンに対しても、何らかのルールを作って共通化できると簡潔に実装できると思うので、まずはルールを整備するところから。

（N予備校Androidはまだルールが整備されていないので、画面によって対応がまちまちだったりします。。。）

### エラー時にどうやってリロード/リトライするか
- 同じ処理をもう一度実行してもらう
- リロードボタンを設置する
- 画面を下に引っ張ってリロードする

上記の画像そのままの順番で、このように対策しています。

上記の画像のように、「保存」ボタンをもう一度押してもらったり、Dialogの「リトライ」ボタンを押してもらうという流れはわかりやすいかと思うのですが、下に引っ張ってもらう方法は何らかの画面表示が必要かもしれません。

新機能を作成するときには、これらのエラー系処理が抜けてしまって、エラーが発生したときに画面が真っ白になってしまうことがあるので、しっかり事前に考慮することが必要です。

# 2. ローディング時の待ち合わせ処理
これはWebとも共通ですが、ローディング中の処理をどうするかを考慮する必要があります。

何度も言いますが、Androidの通信環境は不安定になりやすいために、ローディングが長くなりがちです。

そのローディング画面が実装されていなくて真っ白な画面が続くとユーザが離れてしまうので、何らかの表示が必要になります。

具体的には以下のポイントを考慮します。

### ローディング表示の種類
- 画面全体にローディングを表示する
- 画面の一部にローディングを表示する

N予備校Androidでは、例えば以下のように実装しています。

| 画面全体 | 画面一部 |
|:--:|:--:|
| 教材画面 | 授業詳細モーダル |
| ![device-2019-12-02-174328.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227196/07c5b638-c818-4610-efc5-53ad845f3c74.png) | ![device-2019-12-02-174035.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227196/32dcfb80-eb02-5d11-34f3-302169274e9e.png) |

ユーザから見ると、画面全体のローディングが続くことは恐らく苦痛なので、取得するデータを分割するなどして、なるべく画面一部のローディングで済ませたいです。

いかに素早くユーザに必要なデータを表示できるか、という視点からAPIの設計・分割を行うことが理想でしょう。

より使いやすいアプリにするために、事前のローディング画面の考慮は重要です。

# 3. Activityが破棄されたときの処理
Androidでは、アプリがバックグラウンドに回されると、端末のリソースを確保するためにActivityが削除されることがあります。

Activityが破棄されると、アプリに戻ってきたときに画面の再描画が必要となり、それに伴って入力されていた値が消えてしまうので、必要な情報はActivityが破棄されても残る場所（SavedInstanceStateやDB）に入れる必要があります。

ただし、SavedInstanceStateの容量は[1MBまでの制限](https://developer.android.com/reference/android/os/TransactionTooLargeException.html)があるので全てのデータを持つことはできません。

バックグラウンドから復旧するときに必要なデータと、APIで取得しなおせば良いデータをあらかじめ考慮しておくと、思わぬ問題を防ぐことができます。

Activity破棄の詳しい説明や動作確認の方法についてはいつもこの記事を参考にしています。

[【Android】savedInstanceStateの意味と開発者オプション【初心者向け】](https://qiita.com/yyyske/items/c6e342a9008bebef75bd)

# 4. バックキーで画面を戻す処理
Androidにはバックキーがデフォルトで動作するようになっているので、その制御も考慮する必要があります。

### 画面の戻り先を制御する

例えば、ログイン画面からホーム画面に遷移したときに、何も考えずに実装しているとホーム画面でバックキーを押したときにログイン画面に戻ることになってしまいます。

戻ってほしくない画面にバックキーで戻らないようにするために、Activity/Fragmentによる画面の履歴を管理したり、バックキーが押されたことを検知して処理を上書きする必要があります。

機能を実装していくときには画面遷移図を作成して、各画面におけるバックキーの遷移先を考慮しておくと安心です。

### Toolbarのバックキーによる画面の戻り先も制御する

バックキーだけでなく、Toolbarにも`←`などを置いて画面を戻ることができるようにするでしょう。

`←`のような明らかにバックキーと同じ挙動をするボタンであれば処理もバックキーと同じにすれば良いですが、それ以外の場合にはバックキーと区別して考えます。

例えば、以下の画面のように左上に`x`ボタンをつけるのであれば、そのボタンでどこまで画面を戻す（削除する）のかをバックキーとは別に考慮します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227196/07fae133-7f5a-860b-aa18-9b8d56698787.png" width=30%>

（「物理ベーシック 第0回 はじめに」（無料回）より抜粋）

Toolbarの戻るボタンもバックキーと同じだろうと思っていると後から挙動がおかしくなったりするので、こちらも同じく画面遷移図を作って事前に仕様を決めておきましょう。

# 5. 直リンクでアプリを開く処理
同一アプリ内、またはブラウザなどの他のアプリからURLをタップしたときに、アプリの任意のページに遷移させる必要があるかを考えます。

直リンクの場合は通常の画面遷移と異なるので、必要なAPIが取得できているか、ログインしていない場合に弾くようになっているかも考慮しなければなりません。

一方で、直リンクはユーザのアクセスを容易にする上で必要になることもあるので、機能を実装する前に忘れずに検討したいところです。

___

新機能を実装するときに、これらの要素の考慮漏れがあると後から大変なことになりかねないので、チェックリストとして使っていきたいと思います。

また新たな要素が出てきたら随時更新します。