II...

Preview:

Citation preview

 情報工学実験 II Java/Androidアプリケーション開発実験補足資料

1 Android

1.1 歴史

Googleが開発している携帯情報端末用ソフトウェアのプラットフォームです.2003年にアンディ・ルービン,リッチ・マイナー,ニック・シアーズ,クリス・ホワイトがアメリカカリフォルニア州パロアルトに携帯電話向けソフトウェアプラットフォームを開発するAndroid社を設立しました.2005年にGoogle

が Android社を買収した後,2007年 11月にはGoogle,米クアルコム,独通信キャリアの T-モバイル(T-Mobile International) などが中心となり設立した規格団体 「Open Handset Alliance」(オープン・ハンドセット・アライアンス,OHA)によって携帯情報端末用ソフトウェアのプラットフォームであるAndroidが発表されました.

1.2 バージョン

現在,利用可能なOSの最新バージョンは Android 9.0 です.バージョンごとに提供される API (Application Program Interface) には差異があります.基本的に

は,新しいバージョンほどより多くの API を利用することができます.一方で,古いバージョンでバグがあったり,別の手段が提供されたりしたために推奨されなくなった API も存在します.Androidアプリを開発する上では,OS のバージョンごとに利用可能な API の差異を考慮して互換性

を保つことが重要になります.各バージョンで利用可能なAPI群はAPI Levelによって一意に識別することができます.https://developer.android.com/guide/topics/manifest/uses-sdk-element.

html?hl=ja

1.3 Androidの開発環境

現在のところ,AndroidStudio が標準の IDE (Integrated Development Environment: 統合開発環境)

として開発・提供されています.他にも,Eclipse や,IntelliJ IDEA (著者は経験がありません)と言った他の IDEでも開発することができます.ただ,EclipseとAndroid Developer Tools (ADT) を利用した開発環境へのサポートは,現在終了しているため,特段の理由がなければ,AndroidStudioを利用するべきでしょう.

1.4 アーキテクチャ

Linux をベースとした OS (Kernel) の上に,標準ライブラリや Android ランタイムなどのミドルウェアが乗っています.さらに,ミドルウェアを抽象化したレイヤとして,アプリケーションフレームワーク( Android Framework )のレイヤが提供されています.私たちが開発するアプリケーションは,この図の最上位のレイヤに位置づけられており,Androidが提供するフレームワークを使いながらアプリケーションを開発していくことになります.

1

図 1: Androidのアーキテクチャ

2 Androidの基礎知識

2.1 コンポーネント

Android アプリケーションを開発する上で,最も重要かつ頻繁に利用するコンポーネントは以下の 4

つです.本実験では,最も重要な要素であるActivityについて主に触れますが,より大規模なAndroid

アプリケーションを開発する場合,Serviceや ContentProvider,BroadcastReceiverを活用する場面が多くなります.

• Activity (アクティビティ): Androidにおける1つの画面を構成するコンポーネントです.アクティビティは 1つの Androidアプリケーションの中に複数保持することができ,アプリケーション内でアクティビティ間を移動することも可能です.また,他のアプリケーションのアクティビティを呼び出すこともできます.

• Service (サービス): バックグラウンドである処理を実行するコンポーネントです.アクティビティを終了した後あるいはアプリケーションを終了した後も,継続して実行したい処理を行うために利用します.例えば,端末の状態が変化したことを示すための通知機能等に利用されます.

• ContentProvider (コンテンツプロバイダ): アプリケーションが保有するデータへアクセスするための窓口として利用するコンポーネントです.Androidアプリケーションで利用するデータはファイルシステム(内部保存域)や SQLiteデータベースで保存されていますが,他のアプリケーションはそのデータにアクセスすることはできません.しかし,コンテンツプロバイダというインタフェースを介することで,他のアプリケーションからアクセスあるいは追加・変更が可能な共通のデータソースを作成できるようになります.

• BroadcastReceiver(ブロードキャストレシーバ): アプリケーション全体や,端末全体に渡るメッセージ通知を受け取るコンポーネントです.アクティビティとブロードキャストレシーバの違いとして,アクティビティはメッセージを受け取ると画面が遷移しますが,ブロードキャストレシーバは画面を持たないため,別画面に遷移することなく処理を実行します.

2

2.2 Messaging

Androidアプリケーションを作っていくと,Activityや Serviceなどのコンポーネントが複数作られていきます.それらのコンポーネントを疎に結びつける仕組みとして,Androidでは Intentというメッセージングのフレームワークが用意されています.Intentには,コンポーネントに実行してほしい処理を抽象的に記述します.各々のコンポーネントは,

渡される Intentを元に処理を実行したり,渡ってくるべき Intentへの期待値を表明することができます.また,Intentは,自分のアプリ内のコンポーネントだけでなく,他のアプリのコンポーネントを呼び出すことにも利用されます.

2.3 マニフェストファイル

マニフェストファイルはアプリケーションの設定を行うファイルであり,「アプリ名」,「アイコン」,「パーミッション」などの情報を記述するとともに,どのような「アクティビティ」,「ブロードキャストレシーバ」,「サービス」,「コンテンツプロバイダ」を持つかを記述します.プロジェクトウィンドウで「app/src/main/AndroidManifest.xml」を選択して編集することができます.

AndroidManifest.xmlで設定可能な項目に関しては,以下のURLを参照してください.https://developer.android.com/guide/topics/manifest/manifest-intro.html?hl=ja

2.4 リソース管理

Androidでは,Javaのソースコードと分離した形で静的リソースを管理する仕組みを備えています.具体的には,各プロジェクトの中にある,resディレクトリがこの仕組みを利用するためのディレクトリとなっています.Javaのプログラムから,resディレクトリに配置した静的リソースへのアクセスは,自動で生成されるRオブジェクトを介して行います.

2.4.1 利用可能なリソース

Androidプロジェクトでは,以下に示す静的リソースを利用することができます.ただし,これらの静的リソースは,読み取り専用であり,改変を加えて保存することはできません.

1. String Resource: 定型文など

2. Drawable Resource: ビットマップ、ベクタ画像など

3. Style Resource: UI スタイル、テーマ

4. Menu Resource: メニュー項目

5. Color State List Resource: 状態に対応した色の管理

6. Value Resource: 各種プリミティブ値(Viewコンポーネントの idもこの中)

7. Animation Resource: アニメーション

8. Raw Resource: 音声・動画・画像などの生データ

9. Layout Resource: 画面レイアウト

10. XML Resource: 任意の XML ファイル

3

2.4.2 リソースの利用方法

静的リソースを利用するために,Androidプロジェクトでは各リソースを一意に識別できる ID が割当てられます.IDの割当て方法として,代表的なものは XML の属性(android:idまたは android:name)として記述するものが挙げられます.また,リソースの中には,ファイル名を IDとするものもあります.リソースを利用するときは R.{resource type}.{resource id} と記述します.例えば,アクティビティ

に設置したボタン (id: button1) を参照するときは,R.id.button1 と記述します.

2.5 Androidの独自パッケージ

前回の講義資料にあるとおり,Java言語は,多くのクラスから構成されています.そして,関連しあうクラスをまとめたものをパッケージと呼びます.Androidでは,Java言語で利用可能なパッケージだけでなく,Androidで独自に利用可能なAPIをま

とめたパッケージが用意されています.Androidで利用可能なパッケージは以下に示すように「android」から始まります.利用可能なパッケージについては,以下のURLにまとまっているので,興味があれば各自で調べてほしい.https://developer.android.com/reference/packages.html

表 1: Androidで利用可能な独自パッケージパッケージ名 説明

android.app アプリケーション

android.net 通信機能

android.graphics グラフィックス

android.hardware ハードウェア制御

android.telephony 通話

android.text テキスト

android.view ビュー

android.widget ウィジェット

3 View(ビュー)

本章では,アプリケーション画面を構成する要素 ビュー について説明します.ビューはWidget(ウィジェット)と Layout(レイアウト)の 2種類から構成されています.ウィジェットとは,TextView,EditText,ImageView,Button,CheckBox,RadioButton といった

画面に設置する部品を指しています.レイアウトとは,LinearLayout,RelativeLayout,FrameLayout

といったウィジェットをある形式に取りまとめるものを指しています.

3.1 ウィジェット

ここでは,本実験で開発するアプリケーションで利用するウィジェット(TextView,Button,EditText)について説明します.

• TextViewクラス: 画面上にテキストを表示するために,TextViewクラスを利用します.TextViewクラスには,下記のようなメソッドが用意されており,表示されているテキストを適宜変更することが可能です.

4

表 2: TextViewクラスで利用可能なメソッドsetTextメソッド 表示するテキストデータを指定するときに使用

setTextSizeメソッド 表示するテキストデータのサイズを指定するときに使用setTextColorメソッド 表示するテキストデータの色を指定するときに使用setGravityメソッド 表示するテキストデータの表示位置(左寄せ,右寄せなど)を指定

setCompoundDrawablesメソッド TextViewに付随させる画像イメージを表示するときに使用setTypefaceメソッド 表示するテキストデータのフォントやスタイルを指定するときに使用

• Buttonクラス: アプリケーション画面にボタンを生成するためには,Buttonクラスを利用します.ボタンが押されると,Clickイベントが発生します.また,ボタンが長押しされると,LongClick

イベントが発生します.発生した Clickイベントあるいは LongClickイベントを処理するために,生成したボタンには下記のようにイベントリスナを設定します.LongClickへの処理を実装するには,2行目,3行目を変更すれば良いです.

1 Button button = (Button) findViewById(ここに対応するViewidを入力);2 button.setOnClickListener(new OnClickListener() {3 public void onClick(View v) {4 // クリック時の処理5 }6 });

※この記述方法は無名クラスを利用した場合です.第 1週の課題 2は,簡単化のためにあえて無名クラスを使って記述しています.工夫点として採用するので,これらの記述方法を短くまとめてみてください.

3.2 レイアウト

レイアウトは Android アプリケーションの画面構造を定義します.利用可能なレイアウトとして,LinearLayout,RelativeLayout,FrameLayout,GridLayout,ListView,ScrollViewなどがあり,用途によって使い分けます.

• LinearLayout: Androidの基本的なレイアウトであり,Viewを上 (左)から順にViewを詰めて並べることができます.図 2に示した例では,縦方向の LinearLayoutの中に,横方向の LinearLayout

を導入して,その中に縦方向のLinearLayoutを導入する・・・と言った入れ子構造を利用しています.

• FrameLayout: すでに設置されたView上に新たなViewを配置することができるレイアウトです.例えば,図 3の例では,丸いボタンを FrameLayoutを用いてViewの上に設置しています.

• RelativeLayout: 相対的にViewを配置することができます(例えば,このボタンは button1 の右など).ただ,構造の制御が大変なので,あまり推奨はしません.

4 アクティビティ

2章で述べたとおり,アクティビティはAndroidアプリケーションの 1画面を表すコンポーネントです.本章では,アクティビティについて説明します.

4.1 Androidの画面の構成要素

Androidの画面を作る上で重要なコンポーネントとして,下記のようなものがあります.

• アクティビティ: Androidアプリケーションの 1画面です.画面のライフサイクルや,onClickイベント等の管理を受け持っています.

5

(a) LinearLayoutを使ったレイアウト (b) 内部構造

図 2: LinearLayoutを利用したレイアウト例

• Fragment(フラグメント): アクティビティを再利用可能な小単位に分割したものを指します.例えば,ディスプレイサイズの異なるデバイスへの対応等に利用します.

• ビュー(レイアウト・ウィジェット): 第 3章で解説しました.

4.2 Activityのライフサイクル

各アクティビティにはライフサイクルが存在します。主には,画面が呼び出されてから,必要なくなってメモリから追い出される(破棄される)までの一連の流れをライフサイクルとして扱われます.図 4.2

に示すライフサイクルの各状態は,ライフサイクルコールバックとして,アクティビティクラスに同じ名前で定義されています.それぞれの状態時に行いたい処理がある場合は,該当するメソッドをオーバーライドして定義することになります.

• onCreate: 各アクティビティが一番最初にとる状態です.アクティビティが起動し,画面を構成するまでの仕事をここで行います.主には,XMLで定義したレイアウトを読み込んだり,ビューコンポーネントを取り出したりする処理を実行します.

1 public class MainActivity extends Activity {2 @Override3 protected void onCreate(Bundle savedInstanceState) {4 super.onCreate(savedInstanceState);5 // レイアウトを指定して,Activity がコントロールする View として扱うようにする6 setContentView(R.layout.activity main);7 }8 }

6

(a) FrameLayoutを使ったレイアウト (b) 内部構造

図 3: FrameLayoutを利用したレイアウト例

• onStart(onRestart): アクティビティの画面が構築され,ユーザに見えている状態です.実際にユーザが画面等に触れてインタラクションを実施出来るようになるまでの仕事をここで行います.

• onResume: アクティビティの画面が構築され,ユーザが画面等に触れてアプリケーションとのインタラクションを実施できる状態です.

• onPause: ユーザがアクティビティを離れようとしている状態です.永続化したい情報はこのタイミングで永続化を実施します.

この状態になったアクティビティにユーザが戻ると,onResume の状態へと遷移します.すなわち,この状態になっても,必ずこの後の状態へ遷移して,アクティビティがメモリから破棄されるとは限りません.

• onStop: アクティビティがユーザから見えなくなった状態です.この状態になったアクティビティにユーザが戻ろうとした場合,onRestart の状態を経て onStart へと遷移します.

• onDestroy: アクティビティがシステムによって,メモリから追い出される直前の状態です.この時点で,アクティビティに対するすべての参照を切っておかないと,メモリリークを起こします.一方で,システムによって,アプリケーションのプロセスごと kill された場合には,この状態を経由しません.

7

図 4: 各アクティビティのライフサイクル

5 インテント

本章では,コンポーネント間でやり取りをするための機構であるインテントについて説明します.

5.1 明示的なインテント

明示的なインテントとは,宛先のアプリ(パッケージ名)やActivity(クラス名)を明示的に指定して開く機能です.例えば,アプリケーション内での画面遷移に利用されます.指定先であるパッケージ名とクラス名が分かれば,別のアプリケーションを呼び出すことも可能です.しかし,指定したアプリケーションが存在するという保証はないので,通常,他のアプリと連携する際は「暗黙的なインテント」を使います.

1 /∗ SubActivityを開く ∗/2 Intent intent = new Intent(MainActivity.this, SubActivity.class);3 startActivity(intent);

1 /∗ 他のアプリのパッケージ名とActivity名を名指しして、その画面を開く(明示的な Intent)2 指定のアプリやActivityが存在しないと強制終了するので危険.∗/3 Intent intent = new Intent();4 intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");5 startActivity(intent);

8

5.2 暗黙的なインテント

暗黙的なインテントとは,所望の動作とパラメータを指定すると,Android OSが適当なアプリケーションに取り次いでくれる機能です.例えば

• Webページを見たい

• メールを送りたい

• 地図を見たい

• 電話を掛けたい

と言った要望をインテントとして定義すると,その要望に対処可能なアプリケーションのリストが表示されます.明示的なインテントと比較して,宛先のアプリを明示的に指定する必要がないので柔軟に使用することができます.

1 /∗ 指定のWebページ(https://hoge)をブラウザで開く ∗/2 Intent intent = new Intent();3 intent.setAction(Intent.ACTION VIEW);4 intent.setData(Uri.parse("https://hoge"));5 startActivity(intent);

1 /∗ 宛先と件名、本文を指定してメーラーを開く ∗/2 Intent intent = new Intent();3 intent.setAction(Intent.ACTION SENDTO);4 intent.setData(Uri.parse("mailto:example@example.com"));5 intent.putExtra(Intent.EXTRA SUBJECT, "件名をここに書く。");6 intent.putExtra(Intent.EXTRA TEXT, "本文をここに書く。");7 startActivity(intent);

1 /∗ 電話の発信画面を開き、指定の番号(117)を入力する ∗/2 Intent intent = new Intent();3 intent.setAction(Intent.ACTION VIEW);4 intent.setData(Uri.parse("tel:117"));5 startActivity(intent);

1 /∗ Google PLAYで指定したパッケージ名(jp.tokyometro)のアプリを表示する ∗/2 Intent intent = new Intent();3 intent.setAction(Intent.ACTION VIEW);4 intent.setData(Uri.parse("market://details?id=jp.tokyometro"));5 startActivity(intent);

6 センサ

Android端末にはたくさんの種類のセンサが搭載されています.本章では,これらのセンサをアプリケーションで利用する方法について説明します.

6.1 利用可能なセンサの種類

センサを管理する SensorManagerクラスから取得できるセンサは,現在,表 3のようなものが用意されています.ただし,Android端末によって搭載されているセンサが違うことは留意すること.

9

表 3: 利用可能なセンサ類定数名 センサ名 単位

Android 1.6から

TYPE ACCELEROMETOR 加速度センサ m/s2

TYPE GYROSCOPE ジャイロセンサ rad/s

TYPE LIGHT 照度センサ lux

TYPE MAGNETIC FIELD 磁界センサ uT

TYPE ORIENTATION 傾きセンサ deg

TYPE PRESSURE 圧力センサ hPa

TYPE PROXIMITY 近接センサ cm

TYPE TEMPERATURE 温度センサ ℃

Android 2.3から

TYPE GRAVITY 重力センサ m/s2

TYPE LINEAR ACCELERATION 直線化速度センサ m/s2

TYPE ROTATION VECTOR 回転ベクトルセンサ

Android 4.0から

TYPE AMBIENT TEMPERATURE 温度センサ ℃

TYPE RELATIVE HUMIDITY 湿度センサ %

6.2 センサの利用方法

主に,センサは何かを検知するために継続的に利用されることが多いです.とは言え,常にセンサ値を取得しているのは手間がかかるため,Androidではセンサ値に変化が生じたときに,OSがアプリケーションに通知する仕組みになっています.このとき,アプリケーション側で取得したいセンサ値を指定しておくことで,OSから通知されるセンサ値を限定することができます.アプリケーションでセンサを利用するためには,まず,アクティビティにセンサイベントのリスナを

実装することを宣言します.

1 public class MainActivity extends Activity implements SensorEventListener {

1. センサマネージャを初期化します

2. 利用したいセンサ種類(表 3参照)を指定して、端末に搭載されているセンサの一覧を取得します

3. 所望のセンサがあれば、更新頻度を指定して利用登録します

• SENSOR DELAY FASTEST(限界まで高い頻度)

• SENSOR DELAY GAME(ゲーム用に高めの頻度)

• SENSOR DELAY NORMAL(通常の頻度)

• SENSOR DELAY UI(最低限の頻度)

1 /∗ センサマネージャの初期化 ∗/2 sensorManager = (SensorManager) getSystemService(Context.SENSOR SERVICE);3

4 /∗ 加速度センサの取得 ∗/5 List<Sensor> sensorList = sensorManager.getSensorList(Sensor.

TYPE ACCELEROMETER);6 if (sensorList.size() > 0) {7 /∗ あれば 1番目を取得 ∗/8 Sensor sensor = sensorList.get(0);9 /∗ 加速度センサの利用登録。第 3引数は要求する更新頻度 ∗/

10 sensorManager.registerListener(this, sensor, SensorManager.SENSOR DELAY UI);11 }

10

4. Android OSからの通知を受け取る注意しなければいけないのは,いずれのセンサ値が変化した時も onSensorChangedが呼ばれる点です.どのセンサ値が変化したかを検知するために,センサ種別で条件分岐する必要があります.また,センサ値は event.valuesに配列で入っていますが,配列の何番目にどの値が入っているかは明示されていません.ただ,加速度センサ値なら [X軸,Y軸,Z軸]の順,方位センサなら [方位,

ピッチ,ロール]の順がデファクトスタンダードとなっています.また,センサイベントのリスナを実装するとき,抽象メソッドである onSensorChangedメソッド,onAccuracyChangedメソッドをともに実装する必要があります.抽象メソッドとは,元のインタフェースである SensorEventListenerには中身のないメソッドとして定義されており,このインタフェースを利用するクラスは,必ずこのメソッドをオーバーライドして中身を定義しなければいけないメソッドです.ただ,本プログラムでは,センサの精度が変化したときを考慮しないため,「何もしない」メソッドとして onAccuracyChangedメソッドを定義します.

1 /∗∗2 ∗ 利用登録したセンサの内、最低 1つのセンサ値が変化した時に呼ばれる3 ∗/4 @Override5 public void onSensorChanged(SensorEvent event) {6 /∗ センサの種類で条件分岐 ∗/7 switch(event.sensor.getType()) {8 case Sensor.TYPE ACCELEROMETER:9 /∗ 画面に表示 ∗/

10 accelerometerX.setText( getString(R.string.accelerometer x) + event.values[0] );11 accelerometerY.setText( getString(R.string.accelerometer y) + event.values[1] );12 accelerometerZ.setText( getString(R.string.accelerometer z) + event.values[2] );13 break;14 case Sensor.TYPE ORIENTATION:15 /∗ 画面に表示 ∗/16 azimuth.setText( getString(R.string.azimuth) + event.values[0] );17 pitch.setText( getString(R.string.pitch) + event.values[1] );18 roll.setText( getString(R.string.roll) + event.values[2] );19 break;20 case Sensor.TYPE PROXIMITY:21 /∗ 画面に表示 ∗/22 proximity.setText( getString(R.string.proximity) + event.values[0] );23 break;24 case Sensor.TYPE TEMPERATURE:25 /∗ 画面に表示 ∗/26 temperature.setText( getString(R.string.temperature) + event.values[0] );27 break;28 }29 }30 @Override31 public void onAccuracyChanged(Sensor sensor, int accuracy) {32 }

5. センサの登録解除登録した Listenerは必ず解除してください.解除を忘れるとアプリケーションを終了してもセンサだけが動き続けて,バッテリーを浪費する等の問題が生じる可能性があります.

1 // Listenerの解除2 sensorManager.unregisterListener(this);

11

Recommended