イベントリスナ
では、アクティビティクラスにソースコードを記述していきますが、その前にAndroid開発を行う上で理解しておかなければならない考え方を解説します。
イベントとイベントハンドラとリスナ
Androidでは、ボタンをタップ、アイコンをドラッグなど、ユーザが画面に対して何かの操作を行います。この操作のことを「イベント」といいます。そのイベントに対応して行う処理のことを「イベントハンドラ」といいます。また、イベントの検出を行っているものを「リスナ」といいます。
現段階で、サンプルアプリのボタンをタップしても何も起こらないのはリスナが設定されていないからです。
なお、イベント、イベントハンドラ、リスナという考え方は、実はAndroid独特のものではありません。iOSやデスクトップアプリなど、ユーザの操作に応じて処理を行う類のアプリケーションで共通の考え方です。
Androidでのリスナ設定
Androidでリスナ設定を行う手順は以下の通りです。
- それぞれのイベントに対応したリスナクラスを作成します。
- リスナクラス内の所定のメソッドに処理を記述します。このメソッドがイベントハンドラとなります。
- リスナクラスをnewしてリスナ設定メソッドの引数として渡します。
以下、手順ごとに実際にソースコードを記述しながら解説していきます。
リスナクラス作成
HelloSampleActivityのonCreate()メソッドの下に以下のソースコードを記述します。
public class HelloSampleActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { ~省略~ } private class HelloListener implements View.OnClickListener { @Override public void onClick(View view) { } } }
HelloListenerクラスをprivateメンバクラスとして追記しています。これがボタンのタップというイベントに対するリスナクラスです。
ここで注意するのは、View.OnClickListenerインターフェースを実装(implements)している点です。Androidでは、それぞれのイベントに対応したリスナインタフェースが定義されています。そのほとんどはViewクラスのメンバインターフェースとして定義されていますが、所定のインタフェースを実装する必要があります。
「タップ(クリック)」に対応したインターフェースがView.OnClickListenerインターフェースです。
他にどういったインターフェースがあるのかは、Android API リファレンスのViewクラスページのNested Classesを参照してください。
[Note] メンバクラスと無名クラス
ここでは、リスナクラスをprivateなメンバクラスとして記述していますが、Androidのサンプルでよく見かけるのはリスナクラスを無名クラスとして記述する方法です。これは、どちらの記述でも問題ありません。詳しくは、拙作「業務系JavaエンジニアがAndroid開発をする上で押さえておきたい3つのJava構文」を参照してください。
なお、この連載では、privateなメンバクラスで解説していきます。
処理を記述
View.OnClickListenerインターフェースをimplementsした時点で、onClick()メソッドを実装する必要があります。このonClick()メソッドがイベントハンドラになります。この中に、EditTextから入力された名前を取得して、TextViewに表示させる処理を記述します。
onClick()メソッド内に以下のソースコードを記述します。
public class HelloSampleActivity extends AppCompatActivity { ~省略~ @Override public void onClick(View view) { EditText input = (EditText) findViewById(R.id.etName); // (3) TextView output = (TextView) findViewById(R.id.tvOutput); // (4) String inputStr = input.getText().toString(); // (5) output.setText(inputStr + "さん、こんにちは!"); // (6) } } }
(3)と(4)は似たような記述になっています。Androidでは画面部品をJavaクラス内で扱う場合、まずその部品を取得する必要があります。これは、findViewById()メソッドを使用します。引数として渡すのはandroid:idとして設定されたその画面部品のidを表すR値です。
activity_hello_sample.xmlではEditTextタグに
android:id="@+id/etName"
と記述されています。この「etName」が「R.id」の定数として自動生成されていますので、
findViewById(R.id.etName)
と指定すればこの画面部品を取得できます。
ただし、findViewById()メソッドの戻り値の方はView型ですので、それぞれの画面部品に合わせてキャストする必要があります(リファレンスページを参照)。(4)も同様です。
さて、画面部品が取得できたところで、今度な入力文字列の取得とTextViewへの表示を行いましょう。まず、入力文字列の取得ですが、これは、EditTextクラスのgetText()メソッドを使います。ただし、このメソッドの戻り値はEditable型(リファレンスページ参照)ですので、toString()でString型に変更します。これが(5)です。
一方、TextViewへの表示は、TextViewクラスのsetText()メソッドを使用します。これが(6)です。
リスナ設定
手順の最後として、リスナクラスをnewしてリスナ設定メソッドの引数として渡します。onCreate()メソッド内に以下の(7)~(9)の3行を追記します((1)と(2)はすでに記述されています)。
public class HelloSampleActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // (1) setContentView(R.layout.activity_hello_sample); // (2) Button btClick = (Button) findViewById(R.id.btClick); // (7) HelloListener listener = new HelloListener(); // (8) btClick.setOnClickListener(listener); // (9) } ~省略~ }
(7)ではリスナを設定する画面部品、つまり、Buttonを取得しています。
(8)で手順の1と2で作成したリスナクラスをnewします。
(9)でsetOnClickListener()メソッドでリスナ設定を行います。この時に引数として渡すのが(8)でnewしたリスナオブジェクトです。このsetOnClickListener()メソッドがリスナ設定メソッドですが、どのリスナを設定するのかでメソッド名とその引数の型の組み合わせが変わってきます。タップ(クリック)の場合は、setOnClickListener()メソッドとView.OnClickListener型となっています。
これで、一通りのコーディングが終了しました。
アプリを再起動し、動作確認を行ってください。以下のように、無事表示されれば成功です。
[Note] OpenWnnのバグ?
AVD上で日本語入力を行おうとしたら、以下のようにOpenWnnが強制終了し、日本語入力ができない場合があります。
この現象は実機では確認されず、特定の環境の特定のAVDで起こります。おそらく、AVDのバグと思われます。その場合は、別のAPIレベルのAVDで実行するか、場合によっては英語入力に切り替えるしかありません。