View on GitHub
mixi-inc/AndroidTraining
Androidの基礎知識
この章では、Androidのアプリを作る上で知っておくべき事柄を解説します。

参考:Application Fundamentals | Android Developers
参考:Context | Android Developers
参考:Intents and IntentFilters | Android Developers
参考:Processes and Threads | Android Developers

目次

Components

Android アプリを作る上で、最も重要かつ頻繁に利用するコンポーネントは以下の4つです。

Activity
画面を構成するコンポーネントです。MVC の Controller に相当します。
Service
バックグラウンドで動作するコンポーネントですが、基本はメインスレッドで動作します。 IntentService と呼ばれる特殊な Service コンポーネントは、専用のワーカスレッドで動作します。
ContentProvider
アプリケーションが保有するデータへのアクセスの窓口となるインタフェースです。 多くはSQLiteデータベースへの窓口とするために用いられますが、この他にも、クラウド上のデータへのアクセスや、その他ストレージ上の永続化データへの窓口となることもできます。 ContentProviderというインタフェースを介することで、他のアプリからもデータソースへアクセスしたり、変更したりすることができるようになります。
BroadcastReceiver
アプリ全体や、端末全体に渡るメッセージ通知を受け取るコンポーネントです。 Router のような役割を担います。

Context

Android アプリを作る上で知っておくべきものの1つに、Context があります。 Context は、Android アプリを作る際、様々なところで登場します。

Contextとは?

Android OS の環境やリソースへのアクセスの窓口 となるコンポーネントです。 データベースやファイル、アプリで利用する画像データなどへのアクセスの窓口となるほか、他のアプリとの連携や、アプリ情報へのアクセスの窓口ともなります。 また、 Context はライフサイクルを持っています 。 端末の様々な 状態遷移 の管理も、Context の仕事です。 Context にはいくつかの種類が存在します。アプリを作る際には、 どの種類の Context かを意識する必要があります

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

Contextの種類

Application
Context の一種で、Android アプリ全体を統括するものです。 アプリケーションが起動してから終了するまでのライフサイクルを管理します。
Activity
Context の一種で、1つの画面を統括するものです。MVC モデルの、コントローラに相当する役割を担います。 1つの画面が構成され、バックグラウンドに移るか、終了するまでのライフサイクルを管理します。
Service
Context の一種で、画面を持たず、バックグラウンドで動作します。 バックグラウンドで常に動き続ける常駐型の Service と、都度起動と終了をする Service の2種類があります。 Service が作られてから終了するまでのライフサイクルを管理します。

Resource

Androidアプリでは、様々な種類のリソースに触れることがあります。

アプリケーションリソース

Android プロジェクトの res ディレクトリに格納する各種リソースです。

String Resources
アプリ内で利用する文言などの文字列を、XML に分離して書き出します。文言フォーマットを定義することもできます。 Java のコードに埋め込むのではなく、XML に分離して書きだしておくことが推奨されています。 これにより、多言語化対応が容易になります。
Drawable Resources
アプリ内で利用するグラフィックリソースです。 png 等の画像ファイルの他、XML で簡単なグラフィックを書いたり、UI の状態(押された、選択された、フォーカスされた、通常)ごとのグラフィックの対応付けを書いたりしたものも Drawable Resources になります。 9パッチと呼ばれる特殊なフォーマットにも対応しているため、柔軟なUIパーツを作ることができます。
Color Resources
アプリ内で利用する、色のリソースです。 カラーコードに名前を振って、アプリ内で共有することができます。 このリソースも、Drawable Resources 同様、XML 形式で、View の状態に応じた色の定義をすることができます。
Menu Resources
メニューキーで呼ばれるメニューや、長押しで呼ばれるメニューを定義するのが Menu Resources です。 メニューに表示する文言やアイコンなどを定義することができます。
Style Resources
UIのスタイルを定義します。
Animation Resources
UI のアニメーションをXMLで定義するものです。 Tween アニメーション(移動、拡大縮小など)を扱います。

ストレージリソース

内蔵メモリに保存されるデータへのインタフェース群です。

Database(Content Provider)
SQLite を用いたデータベースです。

ContentProvider というインタフェースを用意することで、他のAndroidアプリ向けにモデルを提供出来るようになります。 OS 標準では、ギャラリーやカレンダーなどのデータベースへのインタフェースとして ContentProvider が利用されています。 通常、ContentProvider で提供されているリソースのアクセスは、ContentResolver オブジェクトを介して行います。

Android のファイルシステムの中では、
/data/data/(package name)/databases
以下のディレクトリに、SQLite3 のデータベースファイルが指定した名前で格納されます。
SharedPreferences
アプリ内で共有する設定ファイルのモデルです。

中身は XML ファイルになっており、各種プリミティブ型と String 型、Set<String> 型のデータを格納することができます。
SharedPreferences の XML ファイルへのアクセス権限を設定することができ、他のアプリからも見える形にすることも可能ですが、セキュリティホールの原因となるため、自分のアプリ以外からはアクセスできないように設定するべきです。

Android のファイルシステムの中では、
/data/data/(package name)/shared_prefs
以下のディレクトリに、指定した名前で保存されます(一部端末で、保存場所が違うことによる不具合が報告されています)。
Internal Storage
データベースファイルや XML ファイル以外に、直接内蔵メモリにファイルを保存するインタフェースも用意されています。

デフォルトでは、アクセス権限は自分のアプリのみしか持っていませんが、SharedPreferences 同様他のアプリからもアクセスできるようにすることができます(非推奨)。

Android では、標準の API として、Internal Storage を使ったキャッシュの仕組みを公開しています。Internal Storage の容量が少なくなると、システムが自動的にキャッシュファイルを削除するようになりますが、自前でアプリが利用するキャッシュファイルの管理(総容量の管理、CRUD)をするべきです。
External Storage
外部ストレージとして、SD カードや、外部ストレージ扱いの内蔵メモリを扱うことができます。

外部ストレージに配置するファイルにはアクセス権限の設定がありませんので、どのアプリからでも読み取ることが可能です。このため、秘匿すべきデータを外部ストレージに書き込むべきではありません。

また、外部ストレージは取り外し可能な場合があるため、常にアクセス可能とは限りません。SD カードのようなメディアを取り外す以外に、ストレージ扱いで USB 接続中や電源を入れた直後も、SD カードがマウント状態とはならない為、External Storage にアクセスできなくなります。

External Storage のデータは
/sdcard/Android/data
に格納されます。

Messaging

アプリを作っていくと、ActivityやServiceなどのコンポーネントが複数作られていきます。

それらの コンポーネントを疎に結びつける仕組みとして、Intentというメッセージングのフレームワークが用意されています。

Intent

Intentとは、Androidにおけるコンポーネント同士を結びつけるメッセージングの仕組みで、 Intentオブジェクト自身は、実行してほしい処理を抽象的に記述するデータ構造を持つものです。

各々のコンポーネントは、渡されるIntentを元に処理を実行したり、渡ってくるべきIntentへの期待値を表明することができます。

Intentは、自分のアプリ内のコンポーネントだけでなく、他のアプリのコンポーネントを呼び出すことにも利用されます。

An intent is an abstract description of an operation to be performed. It can be used with startActivity to launch an Activity, broadcastIntent to send it to any interested BroadcastReceiver components, and startService(Intent) or bindService(Intent, ServiceConnection, int) to communicate with a background Service.

An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed.

明示的Intent
誰に結びつくIntentかを表明しているIntentです。
暗黙的Intent
誰に結びつくIntentかは直接表明せず、より抽象的に、期待する処理をしてくれるコンポーネントを呼び出すためのIntentです。 これにより、例えば、カメラを起動したいときに暗黙的Intentを利用することで、ユーザが好みのカメラアプリを選択できるようになったりします。
IntentFilter
コンポーネント自身が、どのようなIntentを期待しているかを表明する仕組みです。 このフィルタを通過したコンポーネントが、期待通りのIntentを受け取れるものとみなされます。

Processes and Threads

Androidアプリは、アプリごとに割当てられた1つのLinuxプロセスの、1つのスレッド(メインスレッド)で動作します。 プロセスは、アプリの要求に応じて複数作られることもありますが、基本的には1プロセスで動作させることが推奨されています。

プロセス

アプリが起動すると、Linuxプロセスが1つ割当てられます。 アプリの終了が即ちそのプロセスの終了となるとは限らない為、アプリ自体は終了していても、アプリに割当てられたプロセスは生きていることがあります。 割当てられていたプロセスが生きている内に、再度アプリを起動した場合は、そのプロセスが使いまわされます。

プロセスには優先順位が存在し、必要な場合に優先順位の低いプロセスが、システムによってkillされます。 主に、他に優先順位の高いプロセスがより多くのメモリを要求したり、メモリが不足したりした場合に、優先順位に基いてシステムがどのプロセスをkillするか決定します。

優先順位

より上位に位置づけられるプロセスほど優先順位が高く、プロセスをkillされにくくなります。

  1. フォアグラウンドプロセス(Foreground Process)
  2. 可視プロセス(Visible Process)
  3. サービスプロセス(Service Process)
  4. バックグラウンドプロセス(Background Process)
  5. 空プロセス(Empty Process)

アプリ内で、複数のプロセスを持つこともできますが、あまり推奨されません。 どうしても必要な場合に、Activity、Service、Broadcast Receiver、Content Providerの4つのコンポーネントに対して、独自のプロセスで動くよう設定することができます。

スレッド

アプリが起動すると、システムは、割当てられたプロセスの中で、1つのスレッド(メインスレッド)を立ち上げます。 メインスレッドでは、様々なイベントをハンドリングしたり、UIの操作を受け付けたりする必要が有るため、UIスレッドとも呼ばれます。

各々のコンポーネントに対して個別にスレッドを作るわけではないので、同じプロセス上のコンポーネントは全て、UIスレッド上でインスタンス化されます。 このため、キーが押された等のシステムのコールバックメソッドもUIスレッド上で呼ばれます。

もしネットワーク通信やデータベース操作など、時間を要する処理をメインスレッド上で実行すると、すべてのUIのイベントを受け付けることができなくなってしまい、 5秒以上この状態が続くと、ANR(Application Not Responding)と扱われて警告ダイアログが表示されます。

また、他のスレッドからUIを操作することも禁止されています。この操作を行った場合、例外が発生してアプリがクラッシュします。

実習・課題

以下の項目に取り組んでください。

  1. (実習)Android SDK 内の、下記の 2 つのディレクトリにあるコマンドを列挙してください。
    • sdk/tools/
    • sdk/platform-tools/
  2. (実習)上記のディレクトリにパスを通し、下記のコマンドを実行してください。
    • adb devices
    • adb shell
  3. (実習)adb shellコマンドを使って、Android 内のファイルシステムにアクセスし、下記の項目を確認してください。
    • /data/data以下のディレクトリでlsコマンドを打っても、拒否されること
    • /sdcard/Android/data以下のディレクトリの中身を自由に読むことができること
  4. (課題)adbコマンドを使って、下記の項目を実行してください(課題のファイルに、実行したコマンドを記録しておいてください)。
    • 端末のSD カード領域に、ローカルにあるファイルを転送する
    • 端末のSD カード領域から、ローカルにファイルを転送する
    • 課題用サンプルプロジェクトの apk ファイルをコマンド経由で端末にインストールする
    • インストールしたアプリを、コマンド経由でアンインストールする