30

Is it possible to make a secondary class to hold the OnClick Listener? Meaning not being created in the Activity class?

I just find that putting OnClick listeners in the main activity class is just messy and I would rather have them in separate classes. Thanks

4

6 に答える 6

33

もちろん、それは可能です。実装するクラスを作成し、View.OnClickListenerそれを のリスナーとして設定するだけViewです。例えば:

public class ExternalOnClickListener implements View.OnClickListener {

    public ExternalOnClickListener(...) {
        // keep references for your onClick logic 
    }

    @Override public void onClick(View v) {
        // TODO: add code here
    }

}

そして、上記のクラスのインスタンスをリスナーとして設定します。

view.setOnClickListener(new ExternalOnClickListener(...));

onClick(...)パラメーター化されたコンストラクターはオプションですが、実際にロジックを機能させるために何かを渡す必要がある可能性が非常に高くなります。

ただし、クラスを匿名で実装する方が一般的に作業が簡単です。ちょっとした考え。

于 2012-11-21T03:40:37.900 に答える
11

を別のクラスに入れる代わりに、外部でonCLicklistener定義しようとしないのはなぜですか??onClickListeneronCreate()

例:このように

onCreate()

yourViewName.setOnClicklistener(listener):

onCreate() の外側

private OnClickListener listener    =   new OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

        }
    };
于 2012-11-21T03:38:48.273 に答える
7

はい、できます。ただし、リスナーを内部クラスにすることには利点が 1 つあります。それは、アクティビティ クラスのフィールドと変数に直接アクセスできることです。別のクラスにして、リスナーが実際に 5 つのビューにアクセスする必要がある場合、リスナー コンストラクターは次のようになります。

MyListener listener = new MyListener(context, button, textView1, textView2, ratingBar, imageView);

これもちょっとかさばります。リスナーが単純な場合は、別のクラスにしてください。それ以外の場合、読みやすさはあなた次第です。

于 2012-11-21T03:39:08.780 に答える
2

MVP を使用してコーディングする方法を共有しましょう。これは、きれいなコードを作成するための最良の方法です。各クラスには、それを制御するためのインターフェイスが必要です。最も簡単なものをお見せします。

テキスト onClick をトーストし、別のクラスから制御したいとします。仕組みは次のとおりです。インターフェイスを作成することは、相互に接続するだけであり、コードを簡単に確認できます。

  1. その MainActivity クラスのインターフェイスを作成します。

    public interface MainActivityView {
        void showToast();
    }
    
  2. Presenter クラスの別のインターフェイスを作成します。

    public interface IMainPresenter<V extends MainActivityView> {
        /*Generic Type is to make sure it comes from MainActivity class only and to avoid other class to access it.*/
        void onAttach(V mainView);
        void onButtonClick();
    }
    

インターフェイスは、各クラスのメソッドをオーバーライドするだけであることを忘れないでください。

  1. プレゼンター クラスを作成する

    public class MainPresenter<V extends MainActivityView> implements IMainPresenter<V> {
    
        private V mainActivityView;
    
        @Override
        public void onAttach(V mainActivityView) {
            this.mainActivityView=mainActivityView;
        }
    
        public V getView() {
            return mainActivityView;
        }
    
        @Override
        public void onButtonClick() {
            getView().showToast(); //This is the method from MainActivity controlling with this class
        }
    }
    
  2. activity_main.xml レイアウトは省略します。id="@+id/buttonId" のボタンしかないからです。MainActivityClass では、

    public class MainActivity extends AppCompactActivity implements MainActivityView {
    
    Button btn;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            MainPresenter mainPresenter = new MainPresenter();
            mainPresenter.onAttach(this);
    
            btn = findViewById(R.id.buttonId);
    
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mainPresenter.onButtonClick(); //Here, check No.3 again!
                }
             });
        }
    
        @Override
        public void showToast() {
             Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show();
        }
    }
    
  3. 私が言いたいのはそれだけです。クラスでオブジェクトを作成すると、単体テストを行うことができません。そのため、Android で新しいオブジェクトが呼び出されていません。したがって、Presenter クラスでシングルトン パターン (ここでは Lazy Type) を使用できます。はっきりと見えるように、インターフェイスとジェネリックを削除します。

    public class MainPresenter {
    
           private static final MainPresenter mainPresenter = new MainPresenter();
    
           MainPresenter() {}
    
           public static MainPresenter getInstance() {
                   return mainPresenter;
           }
    
           //Some methods here can be get it once you create an object with getInstance();
    }
    

そして、このように MainActivity からそのメソッドを取得できます。このようなオブジェクトを作成する代わりに...

    MainPresenter mainPresenter = new MainPresenter();

こんな感じで取れます…

    MainPresenter mainPresenter = mainPresenter.getInstance();

シングルトン パターンのその他の例は、 https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examplesにあります。

  1. 最後に、 static の使用は、使用するかどうかに関係なくメモリ空間を使用するため、あまり良い選択ではありません。そのため、アプリケーション層内にオブジェクトを作成し、型キャストで取得できます。そのアプリケーション層を単体テストする必要はないと確信しています。

    public class AppLayer extends Application {
    
        private MainPresenter mainPresenter;
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            mainPresenter = new MainPresenter();
        }
    
        public MainPresenter getMainPresenter() {
            return mainPresenter;  
        }
    

また、manifest.xml の Application 内でクラス名を指定する必要があります。

    <application
    android:name=".AppLayer"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    </application>

そして、このように MainActivity の Typecast で取得できます!

    MainPresenter mainPresenter = ((AppLayer)getApplication()).getMainPresenter();
  1. さらなる研究のために、ButterKnife、Dagger 2、SOLID Principles を学ぶことをお勧めします。きれいなコーディングを作成するのに役立ちます。楽しむ!
于 2018-08-16T03:28:28.997 に答える
1

あなたはそれを行うことができます。ただし、アクティビティへの参照も、すべてのビューを含むその属性への参照もないと考えてください。(公開したり、ゲッター メソッドでアクセス可能にしたりしない限り)。

また、ガベージ コレクターがリスナーのメモリを取り戻すのを回避する可能性があるため、リスナーのアクティビティまたは任意のメンバーへの参照を保存する場合は特に注意してください。

于 2012-11-21T03:37:49.240 に答える