Androidアプリ画面構築

これまでに構築してきたWebアプリケーションに加えて,これからAndroidアプリケーションを構築していく。アプリケーションの機能としては,キーワードによる書籍検索と,書籍情報の表示である。アプリケーションの画面構成を以下の図に示す。

新規プロジェクトの作成

まず,Android Studioのインストール時にテスト用のプロジェクトを作成したのと同様に,新しいプロジェクトを"EmptyActivity"で作成する。プロジェクトの名前は何でも良いが,この資料では"BookDatabase"として説明を進める。

新しいEmptyActivityプロジェクトを作成すると,編集領域に以下の2つのファイルが表示される。

Androidアプリにおいて,"Activity"は一つの画面単位であり,画面上に配置されたユーザインタフェースコンポーネント(ボタンやテキスト領域など)が記述された.xmlファイルと,画面の動きをJavaプログラムによって記述した.javaファイルによって構成されている。

画面の構築

キーワード入力画面

まず,キーワード入力画面の構築をレイアウトエディタによって行う。Android Studioの編集領域で"activity_main.xml"に切り替えた上で,下図に示すように,一つの"Plain Text"と,一つの"Button"を画面中央に配置する。

Androidアプリは画面の大きさが異なる様々な端末で動作することが求められているため,各ユーザインタフェースコンポーネントは固定位置ではなく,画面の大きさに合わせて柔軟に配置されるようになっている。そのため,"ConstraintLayout"という仕組みが用意されており,各コンポーネントをどのように配置するかの制約を指定しなければならない。

画面配置の制約は,Android Studioの画面右側にある下図のようなパネルで設定する。ここでは詳しい操作方法を説明しないが,基本的にはプラス(+)ボタンを押すことによって制約が追加され,間隔が伸縮するバネや,固定長の間隔などが指定できるようになっている。二つのコンポーネントがうまく配置されるよう,試行錯誤をしてみてほしい。

ユーザインタフェースコンポーネントの配置が終われば,Javaプログラムから用いる属性の設定を行う。各コンポーネントをクリックすると,画面右側に属性を設定するためのパネルが表示される。特に重要なものは"ID"と呼ばれる属性である(上の図において,配置制約を設定するパネルの上にある)。画面の動作を記述するJavaプログラムでは,この"ID"を用いて各コンポーネントへアクセスするための参照を取得する。今回のプロジェクトでは,TextViewに対して"keywordText",Buttonに対して"searchButton"というIDを設定する(ここで設定したIDとJavaプログラム中で指定したIDが一致していないと正しく動作しない)。

この時点で,一度アプリケーションを実行してみて,構築した画面が正しく表示されるかどうかを確かめてみると良い。

検索結果画面

次に,検索結果を表示する画面を構築する。新しい画面を構築するには,まず,新しいEmptyActivityを追加する。新しいEmptyActivityを追加するには,下図に示すように,Android Studioの画面左側に表示されているプロジェクトのツリー構造において,"app"フォルダを右クリックし,続いて "New"→"Activity"→"EmptyActivity"と選択する。Activityの名前は,"ResultActivity"とする。

ResultActivityという名前で新しいActivityを作成すると,以下の二つのファイルが生成される。

次に,activity_result.xmlを編集して検索結果画面を構築する。検索結果画面には,下図に示すように"ListView"を配置する。IDは"listView"とする。

書籍情報画面

最後に,書籍の詳細情報を表示する画面を構築する。検索結果画面の時と同様に,新しいEmptyActivityを追加する。Activityの名前は"BookInfoActivity"とする。これにより,以下の二つのファイルが生成される。

次に,activity_book_info.xmlを編集して書籍情報画面を構築する。書籍情報画面には,下図に示すように5つの"TextView"を配置する。IDは,順に"titleView","authorView","publisherView","priceView","isbnView"とする。

画面遷移の構築

画面レイアウトの作成に続いて,画面遷移をJavaプログラムによって実現する。まず,キーワード入力画面で検索ボタンが押されたときに,検索結果画面が表示されるようにする。

画面遷移のプログラムを構築する際の手順は概ね以下の通りである。

  1. 画面遷移のトリガーとなるイベント(ボタンのタップなど)が行われた時に実行されるメソッドを用意する。
  2. このメソッド内に,新しいActivityを開くための"Intent"と呼ばれるクラスのインスタンスを作成し,"startActivity()"メソッドでIntentに対応付けられたActivityを開始するようなプログラムを書く。(必要に応じて,新しいActivityにデータを渡すことができる。)
  3. このメソッドを,トリガーとなるユーザインタフェースコンポーネントのコールバックとして指定する。

まず,上記の1.に対応して,MainActivity.javaに以下のメソッドの雛形を追加する。

public void onSearchButtonClicked(View view) {
}

次に,上記の2.に対応して,このメソッド内に以下のプログラムを追加する。

    Intent intent = new Intent(this, ResultActivity.class);
    startActivity(intent);
このプログラムでは,1行目で遷移先画面のActivityに対応するIntentを作成し(ResultActivity.classで遷移先がResultActivityであることを指定),startActivity()でそのIntentに対応するActivityを開始している。

最後に,上記の3.に対応して,このメソッド(onSearchButtonClicked)が検索ボタンを押したときに呼び出されるように,レイアウトエディタ上でボタンをクリックし,下図に示すように,"onClick"属性にメソッドの名前"onSearchButtonClicked"を指定する。

上記のソースコードを記述する上で,import文が自動的に挿入されない場合には,MainActivity.javaの冒頭に以下のimport文を追加する。
import android.content.Intent;
import android.view.View;

この状態でアプリケーションを実行し,検索ボタンを押すと,ResultActivityへ画面遷移するはずである。(実際には,検索結果として表示すべきものを設定していないので,白紙の画面が開くだけである。)

次に,検索結果画面から書籍情報画面への遷移を構築する。まず,検索結果画面で書籍データを表示するために,"SimpleAdapter"というクラスを用いる。以下のプログラムをResultActivity.javaのonCreate()メソッドに追加する。

    ArrayList<HashMap<String, String>> listData = new ArrayList<>();
    listData.add(new HashMap() {
        {put("title", "Androidの基本");}
        {put("author", "立命太郎");}
    });
    listData.add(new HashMap() {
        {put("title", "Androidの応用");}
        {put("author", "立命次郎");}
    });
    listData.add(new HashMap() {
        {put("title", "Androidのススメ");}
        {put("author", "立命三郎");}
    });

    SimpleAdapter adapter = new SimpleAdapter(this,
            listData,   // ListViewに表示するデータ
            android.R.layout.simple_list_item_2, // ListViewで使用するレイアウト(2つのテキスト)
            new String[]{"title","author"},     // 表示するHashMapのキー
            new int[]{android.R.id.text1, android.R.id.text2} // データを表示するID
    );
    ListView listView = (ListView) findViewById(R.id.listView);
    listView.setAdapter(adapter);

ListViewに表示するデータはArrayListにより保持する。また,ArrayListには,表示するデータの内容(今回の場合には書籍のタイトルと著者)をMapとして登録する。今回は,ダミーデータとして3件の書籍情報を登録することとし,Mapにはキー"title"の値として"Androidの基本",キー"author"の値として"立命太郎"を1件目の書籍情報として登録している。

SimpleAdapterには,Listに表示するデータ(ArrayList),使用するレイアウト,表示するデータを表すHashMapのキー,どのキーの値をどの項目に表示するかのIDをパラメータとして渡している。

ListView内の項目がタップされたときに,書籍情報画面へ遷移するためのプログラムは以下の通りである。これを,onCreate()メソッド内に追記する。

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView parent, View view, int position, long id) {
            Intent intent = new Intent(ResultActivity.this, BookInfoActivity.class);
            startActivity(intent);
        }
    });

このプログラムの内容を正確に理解するにはJava言語について詳しい知識が必要になるため,割愛する。これで,3つの画面間で画面遷移が行えるようになるはずである。

演習課題8(→提出先)

上記に従って3つの画面を遷移するAndroidアプリを構築し,動作を確認せよ。

デバッグの仕方

正しくプログラムが書かれていないと,アプリが強制終了したり,正しい情報が表示されなかったりする。そのような場合,Android Studioのデバッガ機能と,Logの出力を用いると原因の特定に便利である。

デバッガ機能

下図に示すように,Android Studioの画面下部にある"Logcat"タブをクリックすると,アプリの詳細な実行ログが出力される。

例えば,アプリが異常終了した場合,実行ログを見て以下のような出力があると,ResultActivity.javaの66行目でNullPointerException(Nullポインタにアクセスした)という例外が発生していることが分かる。

java.lang.NullPointerException: Attempt to invoke virtual method 'int org.json.JSONArray.length()' on a null object reference
        at com.example.htakada.bookdatabase.ResultActivity$1.onSuccess(ResultActivity.java:66)
        at com.example.htakada.bookdatabase.SearchTask.onPostExecute(SearchTask.java:63)
        at com.example.htakada.bookdatabase.SearchTask.onPostExecute(SearchTask.java:12)

プログラムからのログ情報の出力

変数の値を表示したり,どの部分が実行されているのかを確認したりといったように,アプリケーション独自の情報を出力したい場合には,以下のようなプログラムで情報を出力することができる。

Log.d("debug", "onSuccess() called. result = " + result);
出力結果は,上記のLogcatで確認できる。

Copyright © 2018-2020 Hideyuki Takada