14

他のアプリと連携するサービスを書いています。すでにリスナーを持っているビュー(ボタン、テキストビューなど)にリスナーを登録します。それらを自分のリスナーに置き換えて(動作)、いくつかのことを行ってから、リスナーの登録を解除して古いリスナーを復元する必要があります。

  1. onClickListener を持つボタンを持つアプリが実行されています
  2. 私のサービスはUIスレッド内にonClickListenerを登録します+何かをします
  3. 私のサービスは古いリスナーを復元します

-メソッドがあれば簡単view.getOnClickListenerです。次に、古いリスナーを保存し、完了したら新しいリスナーを置き換えることができます。

ビューからリスナーを取得する方法や、同じタイプの複数のリスナーを 1 つのビューにバインドする方法はありますか?

Button btn = (Button) findViewById(R.id.btn1);
btn.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            //do something
        }
    });
// I need to do, but found no solution for that.
View.OnClickListener oldListener = btn.getOnClickListener();

新しいリスナーをビューに登録すると、古いリスナーは上書きされますよね? 両方のリスナー (「新しい」と「古い」) が同時に存在する場合も問題ありません。古いものだけはなくしてはいけません。

編集:残念ながら、割り当て時にリスナーを保存する可能性はありません。ビューコンポーネントから逆方向に取得する必要があります。

ありがとう

4

4 に答える 4

22

mihail のヒントのおかげで (ありがとうございます :)))非表示の APIを使用して、割り当て後にリスナーを取り戻すための解決策を見つけました:

クラスには、ビュー (API 14+) にすべてのリスナーを格納するネストされたandroid.view.Viewクラスがあります。static class ListenerInfo古いバージョンでは、リスナーは android.view.View.

フィールドにはリフレクションでアクセスできます。私の場合(API 14+)、

// get the nested class `android.view.View$ListenerInfo`
Field listenerInfoField = null;
listenerInfoField = Class.forName("android.view.View").getDeclaredField("mListenerInfo");
if (listenerInfoField != null) {
    listenerInfoField.setAccessible(true);
}
Object myLiObject = null;
myLiObject = listenerInfoField.get(myViewObj);

// get the field mOnClickListener, that holds the listener and cast it to a listener
Field listenerField = null;
listenerField = Class.forName("android.view.View$ListenerInfo").getDeclaredField("mOnClickListener")
if (listenerField != null && myLiObject != null) {
    View.OnClickListener myListener = (View.OnClickListener) listenerField.get(myLiObject);
}

そのコードの後 (多くの try-catch ブロックを見逃していました)、myListener オブジェクトは、以前にビューに対して匿名で宣言された onClickListener のインスタンスを保持します。また、他のリスナーでも機能します。「mOnClickListener パラメーター」をリフレクションで必要なものに置き換えて、正しくキャストするだけです。

今後のバージョンでのコード変更により、それが機能しなくなる可能性があることに注意してください。

ここで最後のチュートリアルを見つけました: http://andwise.net/?p=161

于 2013-01-31T10:21:40.633 に答える
3

を実装するクラスを作成するOnClickListener

public static class MyClickListener1 implements OnClickListener{
    Activity mActivity;
    MyClickListener1(Acivity activity){
      mActivity=activity;
    }
    @Override
    public void onClick(View v) {
            //do something
    }
}

public static class MyClickListener2 implements OnClickListener{
    @Override
    public void onClick(View v) {
            //do something
    }
}

そしてあなたのコードであなたはそれらを簡単に使うことができます:

btn.setOnClickListener(new MyClickListener1(this));
btn.setOnClickListener(new MyClickListener2());

または、インスタンスを作成して再利用できます。

OnClickListener listener1 = new MyClickListener1(this);
OnClickListener listener2 = new MyClickListener2();
btn.setOnClickListener(listener1);
btn.setOnClickListener(listener2);

これらのクラスで必要なものをすべて渡すコンストラクターを定義することもできます。私は通常、次のようにアクティビティを渡しますMyClickListener1

編集:ボタンにオブジェクトのようなリスナーを入れたい場合は、タグを使用できます。

btn.setTag(listener1);
btn.setOnClickListener(listener1);

そしてそれを使用するために

OnClickListener old_listener = (OnClickListenr)btn.getTag();
于 2013-01-30T10:50:07.433 に答える
0

OnClickListener の 2 つのインスタンスを作成し、1 つ目または 2 つ目をボタンに割り当てます。

    Button b = (Button) findViewById(R.id.Button1);

    OnClickListener listener_new =  new OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("APP", "NEW CLICK LISTENER ACTIVE");
        }
    };

    OnClickListener listener_old =  new OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("APP", "OLD CLICK LISTENER ACTIVE");
        }
    };

    //setting listener
    b.setOnClickListener(listener_old);
    b.callOnClick();

            //changing listener
    b.setOnClickListener(listener_new);
    b.callOnClick();

            //return your old listener!
        b.setOnClickListener(listener_old);
        b.callOnClick();

追加した:

OnClickListener は View クラスから継承された Button クラスの保護フィールドです。フィールドの名前「mOnClickListener」。反省しても届かない。

void getListener(Button b) {
java.lang.reflect.Field field =  getClass().getSuperclass().getSuperclass().getDeclaredField("mOnClickListener");
}

そのため、ボタンが作成されたコードにアクセスできない場合、ボタンの既存のリスナーを取得することはできません。

ただし、Activity のオブジェクトにアクセスできる場合 (新しいリスナーをボタンに設定しているため、アクセスできることがわかっています)、そのアクティビティのリスナーにボタンを追加できます。既存のボタンを非表示にします。そして、必要に応じてロールバックします。

于 2013-01-30T10:48:54.667 に答える