ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

Android アプリ開発独習メモ #1

Android アプリ開発の勉強を始めた。 とりあえず Android Developers の Getting Started の内容を順に進めていこうと思う。 この記事は適当なメモである。

  • 本記事では “Building Your First App” の “Building a Simple User Interface” の内容まで進める

初心者なので間違いとかあれば指摘お願いします。

開発環境

  • Windows 8
  • JDK 7u21 (Android の開発ガイドには JDK 6 が必要と書かれていて、実際に昔は JDK 7 だとうまくいかないところがあったらしいけど、最近は JDK 7 で大丈夫らしいと聞いたので 7 を入れた。 6 の方がいいかも。)
  • ADT Bundle : http://developer.android.com/sdk/index.html
    • Eclipse なども入ってる Android アプリ開発用の SDK。 新規で始めるならこれを使えばいいらしい。
  • 実機 : Nexus 7

プロジェクト作成

Eclipse を使うなら特に読まなくてもわかりそう。 ただプロジェクトを作るだけ。 コマンドライン使用者向けの情報も書いてあって、なかなかすごい。

プロジェクト作成時に Activity の作成もできる。 今回は例にのっとって “Blank Activity” を作成する。 (アクティビティのクラス名などはデフォルト値とした。)

プロジェクト作成時の項目

  • Application Name : ユーザーに表示される名前。
  • Project Name : ディレクトリ名とかに使われる。 ユーザーには表示されないぽい。
  • Package Name : Java クラスのデフォルト (?) 名前空間となるパッケージ名。 Java の慣例に従い所有するドメイン名を逆向き (jp.ne.hatena.XXX) にしたもので始めるべき。
  • Minimum Required SDK : アプリがサポートする Android の最低バージョンを [API level:title=http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels] で指定する。
  • Target SDK : テストできる Android (?) の最高バージョンを API level で指定する。
  • Compile With : どのバージョンの API level 向けにコンパイルするか (?)

アプリを動かす

これも Eclipse を使ってれば特に難しいところはない。 エミュレータは激重なので使い物にならない。

プロジェクト内の構成 (一部)

アプリを動かす前に重要そうなところだけ紹介されてる。

  • AndroidManifest.xml : アプリの基本的な特性が書かれてる。 最も重要な要素のひとつは uses-sdk 要素である。 アプリがサポートする Android バージョンを指定する (?)
  • src/ : 主なソースファイルを入れておく場所。 ガイドに従ってプロジェクトを作った場合、App アイコンをクリックして起動された場合に実行される Activity クラスがデフォルトで含まれている。
  • res/ : アプリのリソースのためのサブディレクトリを含む。 以下のような。
    • drawable-hdpi/ : Directory for drawable objects (such as bitmaps) that are designed for 高密度 (hdpi) スクリーンのためにデザインされた描画可能な (ビットマップのような) オブジェクトを入れておくディレクト。 他の drawable-XXX ディレクトリはそれぞれのスクリーン密度のためのリソースを含む。
    • layout/ : UI 定義用のファイルを含む。
    • values/ : 文字列や色の定義のための XML ファイルのような、他の (UI 定義用以外の?) 様々な XML ファイルを含む。

実機で動作させる

  1. 開発用 PC と実機を USB 接続する。
    • Windows だと USB ドライバのインストールが必要 : OEM USB Drivers | Android Developers
    • 特にドライバをインストールしなくても通常のデバイスとしては認識されたが、USB デバッグは OEM ドライバをインストールしないとできなかった。
  2. 実機の 「USB デバッグ」 を有効にする
    • 設定の 「開発者向けオプション」 の 「USB デバッグ」 (Android 4.0 以降の場合)。
    • Android 4.2 以降では 「開発者向けオプション」 は最初は隠されている。 設定の 「タブレット情報」 の 「ビルド番号」 を 7 回タップすることで出現する。
  3. Eclipse の 「Run as」 で端末を選択してアプリを実行。

単純な UI を構築する

Android アプリの GUIViewViewGroup オブジェクトの階層構造によって構築される。 View オブジェクトは、通常 buttontext field といった UI 部品であり、ViewGroup オブジェクトは view を格納する不可視の部品である。 ViewGroup は子の view がどのように配置されるかを定義する。 (例えばグリッドや縦方向のリスト、といった配置。)

Android は、View や ViewGroup のサブクラスに対応する XML の語彙を提供しているので、それらの要素の階層構造を使って XML で UI を定義することが可能となっている。

ここでは、プロジェクト作成時に生成された BlankActivity (“Hello World” が表示されるだけのアクティビティ) を編集し、テキスト入力欄と送信ボタンを表示するようにする。 (後からボタン押下時の動作が定義されるが、ここではボタンは存在するだけで押しても反応しない。)

リニアレイアウト (Linear Layout)

今回のプロジェクトの MainActivity で使用されるレイアウトは res/layout/activity_main.xml にある (プロジェクト作成時に自動的に作成されたもの)。 Eclipse でこれを開くと、最初はグラフィカルな表示になる (GUI で配置を設定できる WYSIWYG ツール)。 今回は直接 XML を編集したいので、“activity_main.xml” タブをクリックして XML エディタを開く。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    ... 属性いろいろ ...
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

もともと上記のようになっていて、RelativeLayoutTextView が使われていることがわかる。

今回はここをリニアレイアウトに変更してみる。 リニアレイアウトというのは、水平方向もしくは垂直方向に子要素を並べるものである。 リニアレイアウトを実現するために、ViewGroup の子クラスである LinearLayout を使用する。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
</LinearLayout>

属性の意味は直観的にわかると思う。 (xmlns:tools って上の例の中だけだと要らないと思うけど、書くのが慣例なのかな。) レイアウトに関する詳細は Layout ガイドに書かれている。

テキストフィールド

ユーザーが編集可能なテキスト入力欄は EditText 要素 で表される。

    <EditText android:id="@+id/edit_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="@string/edit_message" />

先に記述した LinearLayout 要素の中に上の例のように EditText 要素を配置する。

android:id 属性 は、要素に対応する View オブジェクトを Java 側から参照するための一意の識別子を与える。 “@” 記号は、あらゆる XML からのリソースオブジェクトを参照するために必要とされる。 “@” 記号の後にリソースの種類 (今回の例では “id”) が続き、さらにスラッシュの後にリソース名 (今回の例では “edit_message”) がくる。

リソースの種類の前の加算記号 (“+”) は、リソース ID を最初に定義する際にのみ必要とされる。 アプリのコンパイル時、プロジェクト内の gen/R.java ファイルに新しいリソース ID を生成するために SDK ツールは ID 名を使用する。 リソース ID が一度定義されてしまえば、この ID に対する他の参照には加算記号は必要ない。 新しいリソース ID を指定する場合にのみ加算記号は必要なのであり、文字列やレイアウトのような具体的なリソースには必要ない (?)。 リソースオブジェクトの詳細は次の項目を参照のこと。

android:layout_width 属性android:layout_height 属性 は、その名のとおりビューの高さや幅を指定する。 この例では “wrap_content” という値が使われているが、これは、そのビューのコンテンツに合うサイズになるようにする指定である。 “match_parent” という値もあり、こちらを使うと親要素の大きさに合うサイズになる。

android:hint 属性 は、テキスト入力欄が空の場合に表示される文字列である。 この例の “@string/edit_message” というのは、別のファイルに定義された文字列リソースを参照する。 今はまだこの文字列リソースを定義していないのでコンパイルエラーが発生するが、この後文字列リソースを定義することで解消される。 今回の例では文字列リソースも要素 ID も同じ edit_message という名前を持っているが、リソースへのリファレンスは常にリソースの種類によって名前空間が分けられているので、同じ名前でも衝突はしない。

リソースオブジェクトについて

リソースオブジェクトは、単に一意な整数値の名前であり、それらはビットマップやレイアウトファイル、文字列といったアプリリソースに結び付けられている。

すべてのリソースには対応するリソースオブジェクトがあり、それらの対応関係はプロジェクトの gen/R.java ファイルで定義される。 R クラスのオブジェクト名を使用することでリソースを参照することが可能である。 さらに、android:id 属性を使用することでビューに対応する任意のリソース ID を生成することも可能である。

R.java ファイルは、コンパイル時に毎回 SDK ツールによって生成される。 このファイルを手で編集することはしてはいけない。

文字列リソースの追加

文字列はハードコーディングするのではなく、文字列リソースとして扱う方が多言語対応したりしやすくなるので良い。

デフォルトでは、res/values/strings.xml に文字列リソース用のファイルがある。 今回の例では、edit_message という名前の文字列リソースへの参照を先に使用したので、edit_message という名前の文字列リソースを追加しなければならない。 (hello_world という名前の文字列リソースへの参照は削除したので、この文字列リソースは削除して良い。)

また、後で使用する button_send という名前の文字列リソースも追加しておく。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">My First App</string>
    <string name="edit_message">Enter a message</string>
    <string name="button_send">Send</string>
    <string name="action_settings">Settings</string>
</resources>

ボタンの追加

送信ボタンを表すための Button 要素 を EditText 要素の後ろに追加する。

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_send" />

このボタンは Activity のコードから参照しないので android:id 属性は必要ない。

テキスト入力欄を広げる

ここまでのコードだと、テキスト入力欄は入力されたテキストに応じて幅が変わるものになっている (android:layout_width="wrap_content" なので)。 高さはともかく、幅に関してはいえば最初から最大幅である方が良いだろう (スクリーンの幅のまだ使用していない部分も使用するようにテキスト入力欄の幅を大きくする)。 LinearLayout の中においては、android:layout_weight 属性 によって weight プロパティを指定することで、それが可能である。

weight の値は、余っている領域のうちどれだけの量をそのビューが消費するかを表す値である。 (自分も含めた) 兄弟要素の weight の合計値に対するそのビューの weight の値が、そのビューが消費できる余っている領域の割合である。

あらゆるビューの weight のデフォルト値は 0 である。 よって、weight を指定されたビューが 1 つしかない場合、そのビューがあまりの領域を全て使用する。

今回の例の場合、EditText 要素に android:layout_weight="1" という属性を付ければよい。 さらに、レイアウトの効率を上げるために、width はゼロ (0dp) にすると良い。

まとめ

  • 開発環境の準備は JDK のインストールと ADT Bundle のインストールと、実機の USB ドライバのインストールのみで完了。
  • UI 用のオブジェクトは大別すると View オブジェクトと ViewGroup オブジェクトの 2 種類。
  • UI 定義は XML ファイルで行うことができる。
  • 文字列リソースや View オブジェクト (リソース ID を与えた場合) などはリソース名で参照することができる。
    • Java のコードからは R.java のプロパティとして。
    • XML からは特定の形式の属性値で。