Androidプログラミング¶
Androidアプリケーション構造¶
Androidアプリケーションはフレームワークによって振る舞い・構造が制限されています。それは、主に小さなアプリケーションが互いに連携できる枠組みを用意しそれを活用して高度な機能を実現するためです。他のOSでは、Androidアプリケーションのようにあるアプリケーションの画面から別なアプリケーションの画面を呼び出し、戻ってくるということは簡単には実現できません。同じく、あるアプリケーションのデータストア(ファイル、データベース)アクセス機能を別なアプリケーションから利用することは簡単には実現できせん。Androidでは、画面間の連携、データストアへのアクセス機能の連携、サービスの連携などが簡単な仕組みで用意されています。
簡単な模式図を次に示します。Androidにおいて画面を制御するActivity、構造化データのCRUDを提供するContentProvider、独立した機能を実行するServiceといった構成要素があります。これらは、1つのアプリケーションの中に押し込めてもよいのですが、別なアプリケーションから利用することもできます。
アーキテクチャの進化¶
アプリケーションが複雑になるにつれ、当初のアプリケーション構造で作成したアプリケーションにはいくつも課題が生じるようになりました。
最大の課題は、Activityの肥大化です。
この課題を解決する良好なアプリケーション構造を導入するアーキテクチャ(設計思想)として、従来のMVC(Model, View, Controller)に替わるMVP(Model, View, Presenter)やMVVM(Model, View, ViewModel)といった構造とその実装を助けるライブラリ群が提供されるようになりました。
また、データについてもSQLiteを直に制御する実装は煩雑であり、またデータの変更をViewに通知するなどの仕組みも必要となります。
データについては、SQLiteにORM(Object Relation Mapper)を被せて実装を楽にするライブラリや、SQLiteのようなSQLベースとは異なるNo SQLのデータベースRealmが提供されるようになりました。さらに、モデルとして管理するデータは、デバイス内に永続化されるものだけでなく、ネットワーク等外部から取得するものもあるため、複数のデータ源泉をまとめて管理できる仕組みが求められています。
アプリケーション構造が密結合なモノリス(それぞれの構造が密に絡み合って出来上がる巨大アプリケーション)とならないよう疎結合に保つことも重要です。
Androidでは、デバイスのOSバージョンが年々更新されるのに伴い、アプリケーションは複数バージョンに対応する必要があります。
こうしたアプリケーションの開発の課題に対応するため、Googleが「Android Jetpack」と呼ぶライブラリ集を2018年頃から整備しています。
UI関連¶
アクティビティ¶
ActionBarActivityが非推奨(deprecated)¶
Android Studio 1.2では空のActivityを生成するとActionBarActivityを継承したクラスが生成されます。これはActivityの上にActionBarを表示するActivityです。しかし、Android 5.0でActionBarに替わりToolBarが導入され、以降はActionBarではなくToolBarを使うことが推奨となりました。ToolBarは他のviewと同じくレイアウトファイルに記述するので、配置を含めていろいろカスタマイズが可能です。
なお、古いAndroidでもsupport library v7(revision 21以降)にToolBarが含まれるのでToolBarを使うことができます。
フラグメント¶
ビュー部品¶
便利なライブラリ¶
バインド・ライブラリ¶
レイアウトXMLに定義した部品とソースコード上の変数とを簡潔に対応付けるライブラリです。
標準Androidコード | バインド利用コード(ButterKnifeの例) |
TextView titleLabel = (TextView) findViewById(R.id.title_label_textview); |
@Bind(R.id.title_label_textview) TextView titleLabel; |
|
|
文字の大きさ¶
レイアウトでビュー個別に文字サイズを設定¶
- 文字の大きさを値で指定
レイアウトXMLファイルのビュー定義でtextSize属性に文字サイズを数値+単位で指定します。
<TextView android:textSize="20sp" ... />
文字サイズの単位は、次のような感じです。
- sp: システム全体の文字スケール(Small, Normal, Large, Extra Large)とフォントに応じて実際のピクセル値に変換される相対的な単位
- dp: 解像度(デバイスの物理的なピクセルの大きさ)によらず、同じ値を指定すれば異なる解像度のデバイスでも同じ大きさで表示される単位
※ DPI(1インチあたりの物理的ピクセル数)をミリミリ計算してるわけではなく、ldpi、mdpi、hdpi、xhdpiのようにDPIのある程度の幅でグループ化して大きさを調整しているので、実際にはデバイスにより多少の大きさのぶれは存在する - px: 解像度(デバイスの物理的なピクセルの大きさ)にもとづく単位
参考¶
モデル関連¶
コンテントプロバイダ¶
永続化¶
SQLiteデータベース¶
Androidは標準でSQLiteを搭載し、アプリケーションフレームワークからSQLiteを利用することができます。
- Androidプログラミング-SQLite
従来から提供される標準ライブラリで、SQLとCursorでデータベースをアクセスします。 - Androidプログラミング-Room
JetPackライブラリ集に含まれるORM(Object Relation Mapper)ライブラリで、DAOとEntityでデータベースをアクセスします。
アプリケーションが使用するSQLiteデータベースファイルの格納場所は次のとおり。/data/data/<アプリケーションのパッケージ名>/databases/<SQLiteデータベースファイル名>
共通¶
リソース¶
Androidアプリケーションプログラムでは、各種定数(文字列、定数、色)をソースファイルにハードコードせずにリソースファイルに記述するスタイルを取っています。また、レイアウトで定義したView部品に付けたIDをソースコードから参照します。これらのリソースを参照するキーとしてリソース名を付けています。
res/valuesに定義するリソース¶
- 文字列
- 整数
- リソースXML
<integer name="max_size">1234</integer>
- Javaソース
int max = res.getInteger(R.integer.max_size);
- リソースXML
- 整数配列
- リソースXML
<integer-array name="numbers"> <item>1</item> <item>1</item> <item>2</item> </integer-array>
- Javaソース
int[] nums = res.getIntegerArray(R.array.numbers);
- リソースXML
ログ¶
Androidのサンプルを見るとほとんどすべてがandroid.util.Log(通称LogCat)を使うものです。
Logクラスに出力したログは、Android OS上のシステムプロセス logd1 にソケット通信で送られ、/dev/log/main のリングバッファに書き込まれます。
リングバッファのサイズは端末にもよりますが、64KBとか256KBといった値2で、このバッファ中にAndroid上のアプリケーションログが書き込まれます。
logcatは、このリングバッファを読みだして標準出力に出すツールです。
リングバッファなので時間がたつとログが書き変わってしまうので、
しかし、これはデバッグを想定した仕組みで、Google開発者向けドキュメントによると、リリース版アプリではLog出力を削除するよう求めています。
運用時にファイルにログを残すには、別な手段を講じる必要があります。
1 Android 5から導入
2 端末を開発者モードに設定するとサイズを増やすことができます
ログの手段¶
- Android標準Log(android.util.Log)
- Java SE標準Log(java.util.logging)
- Timber
- SLF4J + logback-android
- SLF4J + Timber
参考¶
- Android Logging System
Androidのlogd(logger)、logcatの仕組みが図解 - Logging in a multi-module Android project
- Managing Logging in a Multi-Module Android Application
- How to configure java.util.logging on Android?
ハードウェア情報¶
画面¶
画面サイズの取得¶
Activityクラス内で次のように取ります。
Point displaySize = new Point();
getWindowManager().getDefaultDisplay().getSize(displaySize);
Log.d("TEST", "Display size x=" + displaySize.x + ",y=" + displaySize.y);
規約¶
- SQLiteデータベースファイル名(小文字スネークケース)
<アプリケーション名>.db を基本とする。複数のデータベースファイルを使うときは、<アプリケーション名>_<補足名>.dbとする。