2013年10月30日水曜日

コールバックの実装(リスナーとして登録)

コールバックの実装方法に某J氏が悩んでたので説明代わりに記述を( ´_ゝ`)σ)Д`)ツンツン

例として、単純なGridViewのリストをクリックした際に、
Activityでそのクリックイベントをコールバックする仕組みにしました(`・ω・´)シャキーン

コールバックの設定方法として次の2パターンがあります。
1)リスナーとして設定するバターン
2)Activityにインターフェイスを実装するパターン

個人的には、1のリスナーとして設定する方法が好きです(´∀`*)ポッ
なので、まずはリスナーとして登録するパターンを試したいと思います(ΦωΦ)フフフ…

■CustomAdapter.java
GridViewに渡すAdapaterのソースになります。

コールバック用にOnButtonClickListener用の変数 、OnButtonClickListenerメソッド 、
setOnButtonClickListenerメソッドの3つが定義されています。
(それ以外はGridViewを表示させるためのものになります。)

・OnButtonClickListener用の変数
設定されたリスナーを保持するための変数。

・OnButtonClickListenerメソッド(インターフェイス)
コールバック用のインターフェイスを定義します。
コールバックの受け取り側(Activity)で処理の実装を行います。
実装させたいメソッドをここで定義しておきます。例ではonClickとして定義しています。
任意の名前とコールバックを受け取りたい側へ渡す引数を設定する事が出来ますが、
実装側で記述する際には合わせる必要があります。

・setOnButtonClickListenerメソッド
コールバックを受け取りたい側からインターフェースを実装したクラスのインスタンスをセットする

実際のソースコードは次のようになっています。(`・ω・´)シャキーン
package com.example.callback1;

import java.util.ArrayList;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class CustomAdapter extends ArrayAdapter<String> {

 //
 private Context context = null;
 // アダプターに渡したリスト
 private ArrayList<String> data = null;
 //
 private int resource = 0;

 // コールバック用のリスナー
 private OnButtonClickListener mListener;

 /*
  * コールバックの定義
  */
 public interface OnButtonClickListener {

  // クリック処理
  public void onClick(int position);

 }

 /*
  * コールバックの設定
  */
 public void setOnButtonClickListener(OnButtonClickListener listener) {
  mListener = listener;
 }

 public CustomAdapter(Context context, int resource, ArrayList<String> data) {
  super(context, resource, data);
  //
  this.context = context;
  this.resource = resource;
  this.data = data;
 }

 /*
  * 指定された項目を識別するためのIDを取得する
  */
 @Override
 public long getItemId(int position) {
  return position;
 }

 /*
  * 指定された項目を取得する
  */
 @Override
 public String getItem(int position) {
  return data.get(position);
 }

 /*
  * データの項目数を取得する
  */
 @Override
 public int getCount() {
  return data.size();
 }

 /*
  * 1アイテム分のビューを取得.
  * 
  * @param Integer アイテムのポジション番号
  * 
  * @param View 可能な場合不要なビューを再利用する。膨大な量の情報を出力する場合にオブジェクトを可能な限り再利用する。
  * nullの場合には再利用できるオブジェクトがないためオブジェクトを生成する。
  * 
  * @param ViewGroup 選択されたAdapterのビューとなる。GridViewになる。
  */
 @Override
 public View getView(final int position, View convertView, ViewGroup parent) {

  // Viewが無かった場合
  if (convertView == null) {
   // コンストラクタで渡されたレイアウトのリソースIDからViewを取得するため、LayoutInflaterを取得する
   LayoutInflater inflater = (LayoutInflater) getContext()
     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   // レイアウトファイルをViewに変換する(レイアウトに記述されているルートのViewになる)
   convertView = inflater.inflate(resource, null);
  }
  // 取得したビューのキャスト
  TextView viewText = (TextView) convertView;

  //
  viewText.setText(String.valueOf(position));
  //
  viewText.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {
    // TODO Auto-generated method stub
    Log.d("CoustomAdapter", "onClick" + String.valueOf(position));
    if (mListener != null) {
     mListener.onClick(position);
    }
   }

  });

  return viewText;
 }

}

■MainActivity.java(匿名クラスを利用してリスナー登録)
package com.example.callback1;

import java.util.ArrayList;
import com.example.callback1.CustomAdapter.OnButtonClickListener;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.GridView;

public class MainActivity extends Activity {

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

  // GridViewに表示するデータを作成する
  ArrayList<String> list = new ArrayList<String>();

  int length = 100;
  for (int i = 0; i < length; i++) {
   list.add(String.valueOf(i));
  }

  // ArrayAdapterを生成する
  CustomAdapter adapter = new CustomAdapter(getApplicationContext(),
    android.R.layout.simple_list_item_1, list);

  // 匿名クラスでリスナー登録
  adapter.setOnButtonClickListener(new OnButtonClickListener() {

   public void onClick(int position) {
    Log.d("MainActivity", "onClick" + String.valueOf(position));
   }
  });

  // GridViewにカスタムアダプターを設定する
  gridView.setAdapter(adapter);
 }

}
匿名クラスの場合には、次のコードだけでリスナーとしてコールバックを登録できます。
OnButtonClickListenerは、先ほど定義したCustomAdapterクラスのOnButtonClickListenerを指しています。 (上部でインポートしているため。)
  // 匿名クラスでリスナー登録
  adapter.setOnButtonClickListener(new OnButtonClickListener() {
 
   public void onClick(int position) {
    Log.d("MainActivity", "onClick" + String.valueOf(position));
   }
  });
インターフェイス名が被っている場合には、クラス名まで記述する事で回避する事が可能です。
  // 匿名クラスでリスナー登録
  adapter.setOnButtonClickListener(new CustomAdapter.OnButtonClickListener() {
 
   public void onClick(int position) {
    Log.d("MainActivity", "onClick" + String.valueOf(position));
   }
  });
MainActivityは次のように記述しても同じように動作します。
変更点は、リスナーの登録時に匿名クラスを利用せずに、
内部クラスの定義を行って登録を行っています。

■MainActivity.java(匿名クラスを利用せずに内部クラスを作成してリスナー登録)
package com.example.callback1;

import java.util.ArrayList;
import com.example.callback1.CustomAdapter.OnButtonClickListener;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.GridView;

public class MainActivity extends Activity {

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

  // GridViewに表示するデータを作成する
  ArrayList<String> list = new ArrayList<String>();

  int length = 100;
  for (int i = 0; i < length; i++) {
   list.add(String.valueOf(i));
  }

  // ArrayAdapterを生成する
  CustomAdapter adapter = new CustomAdapter(getApplicationContext(),
    android.R.layout.simple_list_item_1, list);

  // 内部クラスをインスタンス化して登録
  adapter.setOnButtonClickListener(new ButtonClickListener());
  // GridViewを取得する
  GridView gridView = (GridView) findViewById(R.id.grid_view);

  // GridViewにカスタムアダプターを設定する
  gridView.setAdapter(adapter);
 }

 /*
  * リスナーを内部クラスとして定義する
  */
 public class ButtonClickListener implements OnButtonClickListener {

  public void onClick(int position) {
   Log.d("ButtonClickListener", "onClick" + String.valueOf(position));
  }

 }

}
簡単な説明をしますと、次の箇所でリスナー用の内部クラスを定義しています。
 /*
  * リスナーを内部クラスとして定義する
  */
 public class ButtonClickListener implements OnButtonClickListener {

  public void onClick(int position) {
   Log.d("ButtonClickListener", "onClick" + String.valueOf(position));
  }

 }
定義した内部クラスをインスタンス化して、それをリスナーとして登録しています。
  // 内部クラスをインスタンス化して登録
  adapter.setOnButtonClickListener(new ButtonClickListener());
こっちの方が登録の部分はスッキリしてますね(゚д゚)(。_。)(゚д゚)(。_。) ウンウン

匿名クラスと内部クラスのどっちを使って記述するようにしてるかというと、
個人的には匿名クラス内に記述する内容が多くなる場合には、
内部クラスを利用して記述するようにしています。

もしくはその時の気分次第⊂二二二( ^ω^)二⊃ブーン

内部クラスのが見やすい気がして見た目はこっちのが好きだったりしますけど、記述が多くなる・・・(´;ω;`)ウッ…

以上です(`・ω・´)ゞビシッ!!

参考URL

0 件のコメント:

コメントを投稿