加速度計の製作

簡単なアプリの製作を体験しましょう。このアプリは、ユーザインタフェースの基本形(テキスト出力とボタン)しか持たないので、これだけでは面白くありませんが、ロボットやゲームのコントロールなどに使えるモーションセンサの他、いろいろな使い道があります。

*プロジェクトの作成

  1. Android Studio を起動し、Welcome 画面で、"Create New Project"を選択
  2. Select a Project Template 画面で、Empty Activity を選んで、Nextボタンをクリック
    各種のActivityの雛型が用意されているが、ここでは、Empty Activityという空の画面から作りこむことにする。Activityについては、後で説明。

    Create New Prohect 1

  3. Configure Your Prohect 画面で、次の図のように設定して、Finishボタンをクリック

    Create New Project 2

  4. しばらく待っていると、MainActivityのViewまたはMainActivityのclass宣言が表示される(初回は、少し時間がかかる)
[参考] アクティビティという言葉がよく出てきますが、Androidのアプリケーションの動作は、アクティビティの状態遷移によって記述されています。アプリの画面を1枚を作るためには、アクティビティクラスを継承したクラス(処理内容や変数のセットと理解しておきましょう)とXMLファイル(画面構成や変数の内容と理解しておきましょう)を用意します。Androidのアプリケーションは、アクティビティの状態遷移(表示、開始、実行、一時停止、再表示など)を繰り返しながら動作しています。そして、各状態に遷移したときの処理と、タップなどのイベント(アプリの操作など)が起こったときの処理を記述するようにプログラムを書いていきます。アクティビティの具体的な状態遷移(またはライフサイクルという)については、WEB等で調べてみてください。後で示すJavaコードの例との対応関係が分かると思います。

*ユーザインタフェースの作成

文字出力とコマンドボタンからなるシンプルなユーザインタフェースを作成します。画面要素をWidgets (またはViewオブジェクト)、画面要素を配置するコンテナをLayout (またはViewGroupオブジェクト)と呼びます。

  1. 左側のProject欄で、app/res/layout/activity_main.xml を探してダブルクリック
    app/res/の下には、画面構成に必要なリソースや文字定数などが保存されます。
  2. View欄上部のツールバーの青四角アイコンで、表示モードを Design に設定
  3. View欄の-/+ボタンで、表示サイズを見やすい大きさに設定(View欄の下の方に表示されている場合もある)
  4. 中央に小さくHello Worldが表示されているので、マウスで選択し、DELキーで削除
  5. View欄上側のツールバーの目玉アイコンをクリックして、Show Margines と Show System UI にチェックを入れる
  6. 動作テストに使用する機種の画面サイズとテーマ(配色など)を設定する
    ここでは、機種 = 5.7インチPhone (Nexus6P), テーマ = プロジェクト名(デフォルト) を使用しています。(注:この設定は、Android Studioの表示設定であり、アプリの表示には関係ありません。)

    Layout 1

  7. ウィジェットの作成
    1. Component Tree欄で、ConstraintLayoutのみが表示されていることを確認
      この状態で、ConstraintLayoutのレイアウトが画面全体に配置されているはず。ConstraintLayout内では、親レイアウトや同じレイアウト内のウィジェット間の相対位置でウィジェット表示場所を定義することができるので、階層的なレイアウト構造を作成せずに簡単に配置ができます。
    2. Parette欄から TextView を View画面上にドラッグして4個配置
    3. さらに、Button をView画面上にドラッグして1個配置

      View

  8. ウィジェットのレイアウト設定
    1. 配置したTextViewとButtonを、それぞれクリックし、Attributes欄で id, Layout, layout_width を下記の図のように設定する。
      ただし、Buttonは、layout_width = 0dp(match_constraint) を選んでください。各 id は、プログラムから参照する際に使用するので、分かりやすい名称に変更しておきます。id を変更すると、操作確認ダイアログが表示されることがありますが、Refactor を選んでプログラムに反映させて下さい。また、位置の設定のため、水色+マークをクリックして、値を入力します。位置の設定をやり直すときは、グレーの丸の部分をクリックします。テキストやボタンが変な位置に配置されて上手く修正できない場合は、View欄のオブジェクトを一旦削除(DELキー)して、作り直してください。

      左上TextView右上TextView
      LayoutLayout
      左中TextView右中TextView
      LayoutLayout
      下段Button
      Layout

  9. ウィジェットの属性設定
    1. 配置したTextViewなどの5つのWidgetsに対して、Attributes欄のCommon AttributesまたはAll Attributesの値を、それぞれ次のように設定する(リストがたたまれている場合は、行頭記号の三角形の部分をクリックして展開)
      (注)onClick は、ボタンをクリックしたときに実行されるメソッド名を指定しています。ただし、Attributes欄でonClickを設定すると、プログラムのコードが読みにくくなるので、コード中で、onClickに対するイベントハンドラーを設定するのが普通です。
    2. 最終的に、各オブジェクト(画面上の部品)の位置がおかしいときは、手動で修正しましょう。

      左上TextView右上TextView左中TextView右中TextView下段Button
      idtextPeaktextPAcceltextCurrenttextCAccelReset
      textPeak Acceleration (m/s2) X:\nY:\nZ:0.0\n0.0\n0.0Current Acceleration (m/s2) X:\nY:\nZ:0.0\n0.0\n0.0RESET
      textSize18sp18sp18sp18sp18sp
      textStyle変更なしBold変更なしBold変更なし
      onClick変更なし変更なし変更なし変更なしpeakReset
      gravityrightrightrightright変更なし
      textColor#ff000000#ff00ffff#ff000000#ff00ffff変更なし
      background変更なし#ff000000変更なし#ff000000変更なし

      View

    3. 編集画面の右上の方にある、3個並んだアイコン(Code, Split, Design)のうち、Codeアイコンをクリックすると、View画面に対応するXML(Extensible Markup Language)のコードが表示される。XMLに慣れている人は、こちらのほうが編集しやすいかもしれない。ViewのProperties設定により、View画面上に表示されなくなったボタンやテキストも、XMLのほうで編集することができる。元に戻すには、編集画面の右上の3個並んだアイコンから、Designを選ぶ。

*コードの記述

JavaやKotlinの書き方は、プログラミングの演習科目で学ぶことにして、とりあえず下記の内容をコピペして作成しましょう。基本的には、アクティビティの変化、ユーザの操作、デバイスの状態変化といったイベントごとに、実行させる処理内容(メソッド)を記述していきます。

  1. 左側のProject欄で、app/java/jp.merl.accel/MainActiviry をダブルクリックすると、ソースコードが表示される
  2. 表示されたJavaのコードを全て消して、下記のリストをコピペする。
    [注意] package の宣言は、自分のパッケージ名に合わせて修正が必要です。また、使用するAPIのバージョンによっては、一部の import 文にも修正が必要な場合があります。
    package jp.merl.kitagawa777;
    
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    // import android.support.v7.app.AppCompatActivity;
    import androidx.appcompat.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.TextView;
    
    import java.text.DecimalFormat;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity implements SensorEventListener {
    
        private SensorManager mSensorManager;
        private Sensor mAccelerometer;
        private final float[] cValues = new float[3];
        private final float[] pValues = new float[3];
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
            List list = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
            if (list.size()>0) {
                mAccelerometer = (Sensor) list.get(0);
            }
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
    
        @Override
        public void onResume() {
            super.onResume();
            if (mAccelerometer != null) {
                mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
            }
        }
    
        public void onStop() {
            super.onStop();
            mSensorManager.unregisterListener(this);
        }
    
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
        }
    
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
                return;
            }
    
            cValues[0] = event.values[0];
            cValues[1] = event.values[1];
            cValues[2] = event.values[2];
    
            for (int i=0; i<3; i++) {
                if(pValues[i] < cValues[i]) {
                    pValues[i] = cValues[i];
                }
            }
    
            DecimalFormat df = new DecimalFormat("###.####");
    
            TextView textCAccel = findViewById(R.id.textCAccel);
            TextView textPAccel = findViewById(R.id.textPAccel);
            StringBuffer cBuf;
            StringBuffer pBuf;
            cBuf = new StringBuffer();
            pBuf = new StringBuffer();
    
            cBuf.append(df.format(cValues[0])).append("\n").append(df.format(cValues[1])).append("\n").append(df.format(cValues[2]));
            pBuf.append(df.format(pValues[0])).append("\n").append(df.format(pValues[1])).append("\n").append(df.format(pValues[2]));
    
            textCAccel.setText(cBuf.toString());
            textPAccel.setText(pBuf.toString());
        }
    
        public void peakReset(View view) {
            TextView textPAccel;
            textPAccel = findViewById(R.id.textCAccel);
            textPAccel.setText("0.0\n0.0\n0.0");
            pValues[0] = 0;
            pValues[1] = 0;
            pValues[2] = 0;
        }
    
    }
    
以下に、上記Javaコードの内容を、おおまかに解説しておきますので、プログラムの流れと雰囲気を掴んでください。

ここでは、全部コピペをしましたが、自分でコードを編集する際に便利な補完機能を紹介します。
  1. CTRL + SPACEキーによりコードの補完ができる
  2. 文法エラーがあると、エディタの右端に褐色の短いラインが表示される
  3. エラーとなっている行の赤文字ににカーソルを置き、ALT + Enterキーを押すと、必要なクラスがインポートされエラーが消えることが多い
    クラスの機能を使用するためには、パッケージ(クラスのカテゴリ)とクラス名を指定する必要がありますが、いちいち調べて書くのは面倒なので、使用するパッケージとクラスの名前を最初に import 文で指定しておきます。import文の左に表示されている+マークをクリックして展開して、現在何がインポートされているか確認できます。今回は、全部まとめてコピペしてしまいました。

*ADB(Android Debug Bridge)による動作確認とデバッグ

PCにテスト用のスマートフォン実機をUSB接続します。実機を持っていない場合は、エミュ(Emulator = PC上でスマホの動作を模擬する機能)を使用することもできますが、センサや無線通信が使えないので、実機の使用をお勧めします。まず、実機を使ってデバッグを行うために、実機の開発者向けオプション設定を行います。
[注意] Androidの実機を持っていない人は、後述のAVD(Android Virtual Device)による動作確認に飛んで下さい。

  1. Androidの設定メニューから、 [端末情報] - [ソフトウエア情報] (または、[システム])を選び、「ビルド番号」を7回タップすると(必要ない場合もある)、[開発者向けオプション]というメニューが、設定画面に追加される
    Androidのバージョンによっては、最初から[開発者向けオプション]がメニューに出ているので、上記の操作は必要ない。
    Androidによっては、「ビルド番号」が表示される階層が異なることがある。
  2. 設定画面から、[開発者向けオプション]に入り、USBデバッグ = ON に設定する
  3. 設定画面から、[セキュリティ]に入り、提供元不明のアプリ = ON に設定する(項目がない場合は、設定の必要はない)
  4. USBケーブルでPCに接続するとPCにUSBドライバがインストールされる
    実機端末が、USBデバッグを許可するか聞いてきた場合はOKする。
    ドライバがインストールされると、PCのデバイスマネージャーに、AndroidデバイスまたはADB Interfaceが表示される。「不明なデバイス」となった場合は、Android Studioユーザガイドなどで適切なドライバーを検索して、インストールを行う。
Android Studioで作成したアプリケーションを走らせ、実機上で動作確認を行います。
  1. ツールバーの Run 'app' ボタン(下図のStart)をクリック
  2. Select Development Targetウインドウが表示されるので、使用するAndroid端末を選んでを選んで、OKボタンをクリック
  3. アプリにエラーがなければ、実機にアプリケーションが転送され、実機上でアプリケーションが起動するので、動作が正しいか確認する
    うまく動作した場合は、実機端末に転送されたアプリケーションを、アプリ一覧から直接起動できる。

    Run 'app'

  4. うまく動作しない場合は、activity_main.xmlとMainActivity.java に文法エラーがないかよく確認する
  5. エラーが見つからない場合は、Android Studioの一番下の方にある Logcat タブをクリックして実行時ログを調べる
    ログ(変数値などの観察)やブレークポイント(プログラムの一旦停止)の設定方法は、3年生の自主課題研究などを参考にしてください。

    LogCat

*スマホへのインストール

実は、ADBを実行する際に、アプリがスマホにインストールされています。アプリ一覧画面でプロジェクト名のアプリを探してみてください。まだ、アイコンを設定していないので、デフォルトのBugdroid(ドロイド君)アイコンになっているはずです。

Test on Nexus7

写真は、Nexus7による動作確認の様子。強く振ると、Peak Accelerationの値が大きくなりますが、あまり強く振って、スマホが飛んでいったりしないよう注意。

*AVD(Android Virtual Device)による動作確認

実機がPCに接続されていない場合は、Android Studioの Run 'app' ボタン(緑三角アイコン)をクリックすると、AVD(Android Virtual Device)というエミュレータが起動します。起動する機種は、Run 'app' ボタンの左側のドロップダウンリストで選択できます。デフォルトでは、NexusとPixelしか用意されていませんが、ドロップダウンリストで、AVD Manager を選択し、+ Create Virtual Device...ボランをクリックすると、他の機種やバージョンの異なるAndroidをインストールすることができます。エミュレータを使えば、多くの種類の実機やAndroidのバージョンを用意しなくても、動作テストができるので便利です。

AVD Manager


環境設定[1/2]

お問い合わせはこちらまで: kitagawa@is.t.kanazawa-u.ac.jp

© Kanazawa Univ., 2013-