Android

(2019年作成資料, 22年確認中)

GUI アプリ開発などについて、鎌田が整えられる文書量なんて知れていますので、細かい話は別のWebテキストなり、教科書などを調べてください。

といっても、すぐに読んでも分からないかと思いますが。

あと、Android の API 群は Java 標準 API とは異なります。

java.util.ArrayList などは、Java 標準パッケージと同様ですが、GUI 関係のライブラリは Android 独自のものが入っていて、例えば、 java.awt.Point の代わりに、 android.graphics.Point があるとか、そんな感じになっています。

以下では Android Studio を利用して、Android アプリ開発の初歩だけ味わってみましょう。

自分のマシンに Android Studio を入れる際 Android SDK や Emulator, Emulator の Accelerator などのセットアップが必要です。Android SDK のファイルだけでも数ギガ必要となります。ご注意ください。 インストール自体は、Android Studio のインストールページを見て指示に従えば大丈夫です。

プロジェクトを開く

とりあえず、サンプルプログラムを動かしながら理解したほうが早いと思うので、 鎌田の作成した簡単なペイントツールの例を動かしてみましょう。といっても、四角形を書けるだけのアプリですが。

Android Studio のインストールがおわったら、Get from VCS を選んで、下記 URL およびファイルの配置場所を指定してください。

  • URL: https://git.nc.ii.konan-u.ac.jp/kamada/androidsample.git

すでに Android Studio をつかいはじめている人は、Fileメニューから New->Project From Version Control->git を選択すれば手続きが始まります。

注: ファイルを取り込んで、プロジェクトのビルド (Gradle build) が終わるまでしばらく待ってください。結構時間がかかります。画面下側のプログレスバーに注意してください。初回インストールだと各種 API ダウンロードも含まれるかもしれません。

こんな感じの画面が出るかと。

astudio0.png

まずは、build project してください。カナヅチマークで大丈夫だと。怒られた場合は、clean project してから build してみてください。

主要なファイルは、

  • app/manifests/AndroidManifest.xml
  • app/java/kobeu.cs.softdev.sample: Java プログラム 以下にある
    • MainActivity: アプリ本体(正確には1画面相当です)
    • CustomView: Draw系コンポーネント
  • app/res: 各種定義ファイルが配置 * layout/activity_main.xml: 部品の配置設定

です。以下は、ファイルメニューで主要なファイルを開いて、design tool で activity_main.xml をみているところです。

astudio1.png

プログラムの起動

run ボタンでプログラムが起動しますが、プログラムは仮想デバイス上で動作するので、まずは仮想デバイスを選択しなくてはいけません。

初回起動時は、画面右端の DeviceManager を開いて、先に Virtual Device を作成しておくとよいでしょう。“Create Device” でマシンと OS を選べます。開発用 PC によっては、仮想デバイスの起動に結構時間がかかります。焦らず気長にいきましょう。

で、あとは緑の再生ボダンを押せば、仮想デバイスへのアプリのインストール&起動がおこなわれます。 あと、下側のRun メニューから実行時出力(下記 Log message)も表示できます。 こんな感じ。

astudio2.png

仮想デバイスはマウスで操作できるはず。

アプリの終了は普段と同じ(赤い停止ボタンでもOK)ですし、デバイスを止めたければ電源ボタンで停止できるはず。

デバッグ

デバッグですが、通常実行の代わりにデバッグボタンで実行可能です。 break point の挿入(行番号右側をクリック)やステップ実行も可能です。

android.util.Log クラスの d(String tag, String msg) メソッドを使って、メッセージを出力していたら、Console 画面にデバッグ出力も出てきます。

デザインツールの利用

まずですが、Android は部品構成は activity_main.xml という XML file で管理していて、プログラム文面上は、setContentView(R.layout.activity_main); とか書くだけになっています。

activity_main.xml を開くと、下画面のようなレイアウトが見えるかと思います。もし XML を見たいって場合は、右上のタブを Design モードから Code モードに切り替えてください。

astudioDesign

様々な画面サイズに対応するため、constraintLayout などの Layout があります。

  • コンポーネント/コンテナの包含・所属関係は、Component Tree (左下)に表示。部品を drag&drop することで、生成&移動も可能です。
  • タイトルやサイズといった各コンポーネントの属性は、**Atribute*画面(右上)で確認/変更可能。
  • Palette (左上)に、部品用のコンポーネントが並んでいます。drag&dropで配置可能。
  • constraintLayout は「ばね」みたいなものがついているので、左右や上下、どちらの部品と位置関係を保つか、〇印から基準物まで drag することで指定しましょう。
  • nest した画面構成にしたければ、container を配置しましょう。

Android では、文字列は、strings.xmlというファイルに集約する文化があります。ボタンの名前とかを一般文字列で書いていたら、Hardcoded textなどという警告が出ると思いますが、fix ボタンを押せば、よろしく修正してくれます。設定はapp/res/values/strings.xml に設定されます。

Style などの警告も出ますが、Attributes画面で適時 style 選択すれば解消されます。

Event Handler

Event Handler ですが、プログラム上で Event Handler を記述することもできますが、型が合致するメソッドを MainActivity に配置すれば、そのメソッド名をボタンの onClick attribute として登録するのでもOKです。

例えば、ボタンクリックは、android.view.View 内の OnClickListener インタフェイスとして実現されているので、

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) { /* ... */ }            
});

とかしてもいいのですが、代わりに

public void reset(View view) { /* ... */ }

とかいうメソッドを準備して、onClick attribute にreset というメソッド名を登録すれば十分です。

今回は、こんな感じ。

public void reset(View view) {
    CustomView v = findViewById(R.id.customView);
    v.reset();
}
public void undo(View view) {
    CustomView v = findViewById(R.id.customView);
    v.undo();
}

ポイント:

  • 各部品は変数ではなく設定ファイルで管理しているので、部品にアクセスする際は、部品の id で検索してアクセスすることになります。例えば、customView の場合 findViewBiId(R.id.customView) で検索して、適切な型変換を施してからアクセスしています。

astudioHandler

Draw 系コンポーネントの解説

Model の作成

まずは Model ですね。四角形のリストを保持したいのですが、android.graphics.RectFがあるので、それを使いましょう。List<RectF> shapesを準備しました。

点を追加するメソッドaddShape(PointF, PointF), 最期の図形を取り除くundo(), 全図形を取り除くreset() も作ってしまいましょう。

これで、モデルはほぼ完了ですね。

っていいたいところですが、入力中の図形を赤色表示するためにModelを少し強化しておきます。 図形の入力は、マウスをpressして(始点)、ドラッグ中の座標は終点候補で、リリースしたタイミングで終点確定となります。 始点をPointF dragBegin, 終点候補をPointF dragCurrentと、フィールドとして設けましょう。 図形入力中は dragBegin, dragCurrentnullでない値をとることとします。

描画ルーチンの作成

Model を表示するためのメソッドを作成しましょう。onDraw(Canvas) です。 ここでも、inteface の規約にのっとってシステムがユーザ定義関数を呼び出すってことがおこなわれています。

android.graphics.Canvas には、描画用のメソッドがあるので、そちらをつかって図形を書きます。 描画中のものがある場合は、赤い四角で描画します。

@Override
protected void onDraw(Canvas canvas) {
    Paint bluePaint = new Paint();
    bluePaint.setColor(Color.BLUE);
    Paint redPaint = new Paint();
    redPaint.setColor(Color.RED);
    for(RectF shape: shapes) {
        canvas.drawRect(shape, bluePaint);
    }
    if(dragCurrent!=null) {
        canvas.drawRect(genRect(dragBegin, dragCurrent), redPaint);
    }
}

やっている中身は、

  • 各四角形を順番に青で塗って、
  • 描画中の四角があれば、赤で塗る

ってだけです。

Event 処理の中身

ユーザ操作は、「マウスをpressして(始点)、ドラッグ中の座標は終点候補で、リリースしたタイミングで終点確定」ってですが、こちらはandroid.view.ViewonTouchEvent(MotionEvent e)を再定義することで定義できます。(参考: android.view.MotionEvent)

e.getAction()MotionEvent の種類をとれるので、

  • MotionEvent.ACTION_DOWN の時は、始点を取得する処理を登録。
  • MotionEvent.ACTION_MOVE の時は、ドラッグ中の終点候補を更新
  • MotionEvent.ACTION_UP の時は、終点確定時の処理を実現

てな感じです。それぞれ、適切に Model の更新を行いえばOKです。 こんな感じ。

@Override
public boolean onTouchEvent(MotionEvent e) {
    PointF point = new  PointF(e.getX(), e.getY());
    switch(e.getAction()){
        case MotionEvent.ACTION_DOWN:
            dragBegin = point;
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            shapes.add(genRect(dragBegin, point));
            dragBegin = dragCurrent = null;
            invalidate();
            performClick();
            break;
        case MotionEvent.ACTION_MOVE:
            dragCurrent = point;
            invalidate();
            break;
    }
    return true;
}
public boolean performClick() {
    super.performClick();
    return true;
}

ポイントは

  • Modelを変更したら、再描画のための **invalidate()** を呼ぶのをわすれないように。
  • toTOuchEvent を override すると、performClick() の意味も変わるので、override しています。