ときまつ日記

プログラマ「トキ」と、広告運用「マツ」でスマホアプリを作成したり色々やっています。分かったことや進捗などをまとめるので、同じ悩みを持っている人と情報共有できればと思います。【トキ→ブログ:https://morelia.tokyo, リポジトリ:https://github.com/b07nji 】

Androidアプリ / イベントとリスナ

こんにちは。
朝一でファンタスティック・ビーストを観に行きたかったのに寝坊した、トキです。
この記事書いたら観にいきます。

さて、今日は画面に入力された値を取得し、表示する方法を学んだのでまとめてみます。
前回記事で作ったビューを改良していく感じで話を進めていきます。
tokimatsu.hatenablog.com
ちなみに、動作環境はこんなです。

OS macOS 10.14.1
IDE Android Studio 3
言語 Java11

今回は、画面の入力項目を埋めた後にセーブボタンを押すと入力値をリストで表示するようにしてみたいと思います。改良後のアプリのイメージはこんな感じ↓

f:id:TokiMatsu:20181202124542p:plain

コードも全て載せておきます↓
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#A1A9BA"
    android:orientation="vertical">


    <EditText
        android:id="@+id/etName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="25dp"
        android:layout_marginTop="5dp"
        android:background="#ffffff"
        android:inputType="text"
        android:hint="なまえをいれてください"/>

    <RadioGroup
        android:id="@+id/rgSex"

        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:background="#0000ff"
        android:orientation="horizontal"
        android:paddingBottom="10dp"
        android:paddingTop="10dp">

        <RadioButton
            android:id="@+id/rbMale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="25dp"
            android:layout_marginRight="25dp"
            android:background="#ffffff"
            android:text="@string/rb_male" />

        <RadioButton
            android:id="@+id/rbFemale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ffffff"
            android:text="@string/rb_female"/>
    </RadioGroup>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="#0000ff"
        android:orientation="horizontal">

        <CheckBox
            android:id="@+id/cdKinobou"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="25dp"
            android:background="#ffffff"
            android:text="@string/cb_kinobou"/>

        <CheckBox
            android:id="@+id/cdTate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="25dp"
            android:background="#ffffff"
            android:text="@string/cb_tate"/>

    </LinearLayout>

    <Spinner
        android:id="@+id/spType"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="#ffffff"
        android:entries="@array/sp_type"
        android:paddingBottom="5dp"
        android:paddingTop="5dp" />

    <Button
        android:id="@+id/btSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="セーブする"/>

    <ListView
        android:id="@+id/lvData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btSave = findViewById(R.id.btSave);
        CreateCharacterListener listener = new CreateCharacterListener();
        btSave.setOnClickListener(listener);

    }

    //リスナクラス
    private class CreateCharacterListener implements View.OnClickListener {

        //イベントハンドラ
        @Override
        public void onClick(View view) {


            ArrayList<String> data =new ArrayList<>();

            //名前
            EditText name = findViewById(R.id.etName);
            data.add(name.getText().toString());

            //性別
            RadioGroup rg = findViewById(R.id.rgSex);
            int rbId = rg.getCheckedRadioButtonId();
            RadioButton rbSex = findViewById(rbId);
            data.add(rbSex.getText().toString());


            //装備
            CheckBox cdKinobou = findViewById(R.id.cdKinobou);
            CheckBox cdTate = findViewById(R.id.cdTate);

            if (cdKinobou.isChecked()) {
                data.add(cdKinobou.getText().toString());
            }

            if (cdTate.isChecked()) {
                data.add(cdTate.getText().toString());
            }

            //職業
            Spinner sp = findViewById(R.id.spType);
            String type = (String)sp.getSelectedItem();
            data.add(type);


            //リスト表示
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                        MainActivity.this,
                       android.R.layout.simple_list_item_1, 
                       data);
            ListView list = findViewById(R.id.lvData);
            list.setAdapter(adapter);

        }
    }
}

アプリの起動~画面表示までの流れ

そもそも、Androidアプリの起動から画面を返すまでのプロセスはどんな感じなのでしょうか。
こんな感じです。

  1. アプリが起動すると、まずapp/java/任意のパッケージ名/MainActivity.javaのonCreate()メソッドが実行され、
  2. onCreate()メソッド内のsetContentView(R.layout.ファイル名)メソッドが表示するビューをセットする。

setContentView()に渡しているR.layout.ファイル名は、app/res/layout/配下のxmlファイルと対応しています。なので、表示したい画面を変えたいときはこいつに渡すパラメータを変えればいいんですね。

しかし、ここまではあらかじめ用意された画面を返すだけです。今回やりたいのは、onCreate()メソッドがセットした画面への入力値を受け取って、再度同じ画面にその入力値を表示すること。

その前に、この処理を実装するために抑えるべきキーワードをまとめてみます。

イベント・リスナ・イベントハンドラ

これはAndroidアプリ特有でなく一般的な考え方なのですが、
ユーザが画面に対して行った操作をイベント、そのイベントの検出を行うプログラムをリスナ、そしてリスナが検出したイベントに対して行う処理をイベントハンドラと呼びます。
なので、今回やりたいことをあえて言い直すと、

ユーザが値を入力してセーブボタンをタップする(イベント)と、リスナがそれを検知し、イベントハンドラが入力値を受け取ってリスト形式で画面に表示する、といった感じでしょうか。

それでは、それぞれ実装していきます。

リスナの実装

タップ(クリック)というイベントを検知するには、View.OnClickListenerインタフェースを実装します。インタフェースなので、こいつを実装した時点でView.OnClickListenerに定義されているonClick()メソッドを実装する必要があります。これがイベントハンドラになります。

MainActivity.java

    //リスナクラス
    private class CreateCharacterListener implements View.OnClickListener {

        //イベントハンドラ
        @Override
        public void onClick(View view) {
            //処理

        }
    }

イベントハンドラの実装

それではイベントハンドラonClick()を実装していきます。

テキストボックス
まずは名前の取得から。
名前を入力するテキストボックスは、EditTextタグで生成されています。
この部分です。
activity_main.xml

    <EditText
        android:id="@+id/etName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="25dp"
        android:layout_marginTop="5dp"
        android:background="#ffffff"
        android:inputType="text"
        android:hint="なまえをいれてください"/>

EditTextを取得するには、findViewById()メソッドを使います。

MainActivity.java

            //リスト生成
            ArrayList<String> data =new ArrayList<>();

            //名前の取得
            EditText name = findViewById(R.id.etName);

            //リストに追加
            data.add(name.getText().toString());

findViewById()にactivity_main.xmlのEditTextタグのidを渡すことで、テキストボックス内の値を取得できます。JavascriptでDOM操作とかする人はイメージつきやすいですかね。

ちなみに、最終的にリスト形式で取得した値を表示したいのでリストを生成してます。

ラジオボタン
ラジオボタンを生成するRadioButtonタグは、RadioGroupタグでネストされてます。
activity_main.xml

    <RadioGroup
        android:id="@+id/rgSex"

        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:background="#0000ff"
        android:orientation="horizontal"
        android:paddingBottom="10dp"
        android:paddingTop="10dp">

        <RadioButton
            android:id="@+id/rbMale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="25dp"
            android:layout_marginRight="25dp"
            android:background="#ffffff"
            android:text="@string/rb_male" />

        <RadioButton
            android:id="@+id/rbFemale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ffffff"
            android:text="@string/rb_female"/>
    </RadioGroup>

なので、RadioGroupタグをまず取得し、その要素であるRadioButtonを、かつチェックされたものを取得します。

MainActivity.java

            //性別
            RadioGroup rg = findViewById(R.id.rgSex);
            int rbId = rg.getCheckedRadioButtonId();
            RadioButton rbSex = findViewById(rbId);
            data.add(rbSex.getText().toString());

チェックボックス
お次はチェックボックス

activity_main.xml

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="#0000ff"
        android:orientation="horizontal">

        <CheckBox
            android:id="@+id/cdKinobou"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="25dp"
            android:background="#ffffff"
            android:text="@string/cb_kinobou"/>

        <CheckBox
            android:id="@+id/cdTate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="25dp"
            android:background="#ffffff"
            android:text="@string/cb_tate"/>

    </LinearLayout>

これまたLinearLayoutでネストされてます。が、今回は愚直にチェックボックスのidを直接使って取得しました。(チェックボックスが可変個だった場合対応できないので、改良する必要がありますね汗)

MainActivity.java

            //装備
            CheckBox cdKinobou = findViewById(R.id.cdKinobou);
            CheckBox cdTate = findViewById(R.id.cdTate);

            if (cdKinobou.isChecked()) {
                data.add(cdKinobou.getText().toString());
            }

            if (cdTate.isChecked()) {
                data.add(cdTate.getText().toString());
            }

チェックボックスを取得し、isCheck()メソッドでチェックされてる場合にリストに追加してます。

プルダウン
最後はプルダウン。

activity_main.xml

    <Spinner
        android:id="@+id/spType"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="#ffffff"
        android:entries="@array/sp_type"
        android:paddingBottom="5dp"
        android:paddingTop="5dp" />

MainActivity.java

            //職業
            Spinner sp = findViewById(R.id.spType);
            String type = (String)sp.getSelectedItem();
            data.add(type);

Spinnerを取得し、getSelectedItem()で選択されたものの値を取得しています。


リスト表示

これで全ての値を取得しリストに詰め終わったので、ListViewに渡してビューに表示させます。

MainActivity.java

            ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, data);
            ListView list = findViewById(R.id.lvData);
            list.setAdapter(adapter);

ArrayAdapterやListViewについては、こちらの記事でまとめてます。

リスナの登録

最後は、リスナ設定です。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //セーブボタンを取得
        Button btSave = findViewById(R.id.btSave);
        
        CreateCharacterListener listener = new CreateCharacterListener();
   //セーブボタンにリスナを登録
        btSave.setOnClickListener(listener);

    }


お疲れ様でした。
これで入力値を画面に表示することができました。

まとめ

今回は、画面に入力された値を取得し画面に表示する方法についてまとめてみました。
手順を簡単にまとめると、

  1. リスナクラスの作成
  2. イベントハンドラを実装
  3. リスナクラスの登録

てな感じです。


ここまでご覧になられた方、ありがとうございました。
次回は、データベースに接続してほんとのセーブ機能を作っていきたいと思います。


それではまた〜