Подтвердить что ты не робот

Android - setOnClickListener против OnClickListener против View.OnClickListener

Насколько я понимаю, когда я создаю объект кнопки, который прослушивает щелчок, я должен:

  1. Создать объект кнопки
  2. Используйте OnClickListner чтобы заставить его слушать щелчок пользователя
  3. Используйте onClick для выполнения действий после того, как пользователь нажимает кнопку

Сейчас,

  • Где setOnClickListener вписывается в вышеуказанную логику?
  • Кто на самом деле слушает нажатие кнопки?
  • setOnClickListener?
  • OnClickListener?
  • View.OnClickListener?
  • Каковы различия между этими тремя?

Вот что я нашел в Android Dev:

//The example below shows how to register an on-click listener for a Button.

// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

protected void onCreate(Bundle savedValues) {
    ...
    // Capture our button from layout
    Button button = (Button)findViewById(R.id.corky);
    // Register the onClick listener with the implementation above
    button.setOnClickListener(mCorkyListener);
    ...
}

Вам также может быть удобнее реализовать OnClickListener как часть вашей Activity. Это позволит избежать дополнительной нагрузки на класс и распределения объектов. Например:

public class ExampleActivity extends Activity implements OnClickListener {
    protected void onCreate(Bundle savedValues) {
        ...
         Button button = (Button)findViewById(R.id.corky);
         button.setOnClickListener(this);
    }

    // Implement the OnClickListener callback
    public void onClick(View v) {
      // do something when the button is clicked
    }
}
4b9b3361

Ответ 1

Логика проста. setOnClickListener принадлежит шагу 2.

  • Вы создаете кнопку
  • Вы создаете экземпляр OnClickListener *, как в этом примере, и переопределяете метод onClick.
  • Вы назначаете эту OnClickListener на эту кнопку, используя btn.setOnClickListener(myOnClickListener); в своих фрагментах/действиях onCreate -метод.
  • Когда пользователь нажимает кнопку, вызывается функция onClick назначенного OnClickListener.

* Если вы import android.view.View; используете View.OnClickListener. Если вы import android.view.View.*; или import android.view.View.OnClickListener; используете OnClickListener, насколько я понимаю.

Другой способ - позволить вам наследование/фрагмент наследовать от OnClickListener. Таким образом вы назначаете свой фрагмент/активность в качестве слушателя для своей кнопки и реализуете onClick как функцию-член.

Ответ 2

Предположим, что у нас есть 3 кнопки, например

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        // Capture our button from layout
        Button button = (Button)findViewById(R.id.corky);
        Button button2 = (Button)findViewById(R.id.corky2);
        Button button3 = (Button)findViewById(R.id.corky3);
        // Register the onClick listener with the implementation above
        button.setOnClickListener(mCorkyListener);
        button2.setOnClickListener(mCorkyListener);
        button3.setOnClickListener(mCorkyListener);

    }

    // Create an anonymous implementation of OnClickListener
    private View.OnClickListener mCorkyListener = new View.OnClickListener() {
        public void onClick(View v) {
            // do something when the button is clicked 
            // Yes we will handle click here but which button clicked??? We don't know

        }
    };

}

Итак, что мы будем делать?

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        // Capture our button from layout
        Button button = (Button)findViewById(R.id.corky);
        Button button2 = (Button)findViewById(R.id.corky2);
        Button button3 = (Button)findViewById(R.id.corky3);
        // Register the onClick listener with the implementation above
        button.setOnClickListener(mCorkyListener);
        button2.setOnClickListener(mCorkyListener);
        button3.setOnClickListener(mCorkyListener);

    }

    // Create an anonymous implementation of OnClickListener
    private View.OnClickListener mCorkyListener = new View.OnClickListener() {
        public void onClick(View v) {
            // do something when the button is clicked
            // Yes we will handle click here but which button clicked??? We don't know

            // So we will make
            switch (v.getId() /*to get clicked view id**/) {
                case R.id.corky:

                    // do something when the corky is clicked

                    break;
                case R.id.corky2:

                    // do something when the corky2 is clicked

                    break;
                case R.id.corky3:

                    // do something when the corky3 is clicked

                    break;
                default:
                    break;
            }
        }
    };

}

Или мы можем это сделать:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        // Capture our button from layout
        Button button = (Button)findViewById(R.id.corky);
        Button button2 = (Button)findViewById(R.id.corky2);
        Button button3 = (Button)findViewById(R.id.corky3);
        // Register the onClick listener with the implementation above
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // do something when the corky is clicked
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // do something when the corky2 is clicked
            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // do something when the corky3 is clicked
            }
        });

    }

}

Или мы можем реализовать View.OnClickListener, и я думаю, что это лучший способ:

public class MainActivity extends ActionBarActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        // Capture our button from layout
        Button button = (Button)findViewById(R.id.corky);
        Button button2 = (Button)findViewById(R.id.corky2);
        Button button3 = (Button)findViewById(R.id.corky3);
        // Register the onClick listener with the implementation above
        button.setOnClickListener(this);
        button2.setOnClickListener(this);
        button3.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        // do something when the button is clicked
        // Yes we will handle click here but which button clicked??? We don't know

        // So we will make
        switch (v.getId() /*to get clicked view id**/) {
            case R.id.corky:

                // do something when the corky is clicked

                break;
            case R.id.corky2:

                // do something when the corky2 is clicked

                break;
            case R.id.corky3:

                // do something when the corky3 is clicked

                break;
            default:
                break;
        }
    }
}

Наконец, здесь нет реальных различий. Просто "Лучше, чем другой"

Ответ 3

Обратите внимание, что для простоты я сделал ссылку только на первый фрагмент кода i.e.,

// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

protected void onCreate(Bundle savedValues) {
    ...
    // Capture our button from layout
    Button button = (Button)findViewById(R.id.corky);
    // Register the onClick listener with the implementation above
    button.setOnClickListener(mCorkyListener);
    ...
}

setOnClickListener(View.OnClickListener l) является общедоступным методом класса View. Класс Button расширяет класс View и поэтому может вызвать метод setOnClickListener(View.OnClickListener l).

setOnClickListener регистрирует обратный вызов для вызова при нажатии кнопки просмотра (кнопка в вашем случае). Эти ответы должны отвечать на ваши первые два вопроса:

1. Где setOnClickListener соответствует приведенной выше логике?

Отв. Он регистрирует обратный вызов при нажатии кнопки. (Подробно поясняется в следующем параграфе).

2. Какой из них действительно прослушивает нажатие кнопки?

Отв. setOnClickListener - метод, который фактически прослушивает нажатие кнопки.

Когда я говорю, что он регистрирует обратный вызов для вызова, я имею в виду, что он будет запускать View.OnClickListener l, который является входным параметром для метода. В вашем случае это будет mCorkyListener, упомянутое в button.setOnClickListener(mCorkyListener);, которое затем выполнит метод onClick(View v), указанный в

// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

Далее, OnClickListener - это определение интерфейса для обратного вызова, вызываемого при нажатии кнопки просмотра (кнопка в вашем случае). Просто говоря, когда вы нажимаете эту кнопку, выполняются методы внутри mCorkyListener (потому что это реализация OnClickListener). Но OnClickListener имеет только один метод, который onClick(View v). Поэтому любое действие, которое необходимо выполнить при нажатии кнопки, должно быть закодировано в этом методе.

Теперь, когда вы знаете, что означают setOnClickListener и OnClickListener, я уверен, что вы сможете провести различие между ними. Третий член View.OnClickListener фактически OnClickListener. Единственная причина, по которой у вас есть View., предшествующая ей, - это разница в статусе import в начале программы. Если у вас есть только import android.view.View; в качестве оператора импорта, вам нужно будет использовать View.OnClickListener. Если вы упомянете об одном из этих операторов импорта: import android.view.View.*; или import android.view.View.OnClickListener; вы можете пропустить View. и просто использовать OnClickListener.

Ответ 4

Вид - суперкласс для всех виджетов, а интерфейс OnClickListener принадлежит этому классу. Все виджеты наследуют это. View.OnClickListener - это то же самое, что и OnClickListener. Вам нужно будет переопределить метод onClick (View view) из этого прослушивателя, чтобы выполнить действие, которое вы хотите для своей кнопки.

Чтобы сообщить Android о событиях щелчка для виджета, вам нужно сделать:

widget.setOnClickListener(this); // If the containing class implements the interface
// Or you can do the following to set it for each widget individually
widget.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Do something here
    }
});

Параметр "Вид", переданный в методе onClick(), просто позволяет Android знать, что нажата точка просмотра. Это может быть Button или TextView или что-то еще. Вам нужно установить OnClickListener для каждого виджета или просто сделать класс, содержащий все эти виджеты, реализовать интерфейс. В этом случае у вас будет общий метод onClick() для всех виджетов, и все, что вам нужно сделать, это проверить идентификатор представления, который передается в этот метод, а затем сопоставить его с идентификатором для каждого элемента, который вы хотите, и принять действие для этого элемента.

Ответ 5

  • Прежде всего, нет разницы между View.OnClickListener и OnClickListener. Если вы просто используете View.OnClickListener напрямую, тогда вам не нужно писать -

    import android.view.View.OnClickListener

  • Вы устанавливаете экземпляр OnClickListener (например, myListener named object) в качестве слушателя для представления через setOnclickListener(). Когда запускается событие click, этот myListener получает уведомление и вызывается метод onClick(View view). Вот где мы делаем свою собственную задачу. Надеюсь, это поможет вам.

Ответ 6

Каждый раз, когда я получаю эту ошибку:

2019-06-14 00:24:27.880 21551-21551/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: de.mi12.snowflake, PID: 21551
    java.lang.RuntimeException: Unable to start activity ComponentInfo{de.mi12.snowflake/de.mi12.snowflake.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at de.mi12.snowflake.MainActivity.onCreate(MainActivity.java:72)
        at android.app.Activity.performCreate(Activity.java:7009)
        at android.app.Activity.performCreate(Activity.java:7000)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) 
        at android.app.ActivityThread.-wrap11(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6494) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 

Мой класс выглядит так. У кого-нибудь есть идея?

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button startButton;
    private Button EndeButton;
    private Button RanglisteButton;
    private Button SpielregelnButton;
    private Button OptionButton;

    /**
     * Startet die Applikation und Activity. Als Bildschirmeigenschaften wird
     * die obere Titelleiste ausgeblendet und der Vollbildschirm als Flag
     * gesetzt. Als View wird das XML-Layout activity_main geladen. Zudem werden
     * die verschiedenen Buttons geladen und für jeden Button ein
     * onClickListener registriert. Als letztes wird der Pfad des Textdokuments
     * in dem die Punktestände gespeichert werden übergeben und initialisiert.
     *
     * @param savedInstanceState Übergibt das Bundle des letzten gespeicherten Zustandes der
     *                           Activity, falls vorhanden.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        this.getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN
        );

        setContentView(R.layout.activity_main);

        // fuehrt den Orientation Check aus und ggf aenderung der sensoren
        Orientation.getAusrichtung(this);

        // -------------------Holt die Buttons und übergibt ihnen den
        // OnClickListener------------------------------------------

        startButton = (Button) findViewById(R.id.menu_start);
        startButton.setOnClickListener(this);

        EndeButton = (Button) findViewById(R.id.menu_beenden);
        EndeButton.setOnClickListener(this);

        RanglisteButton = (Button) findViewById(R.id.menu_rangliste);
        RanglisteButton.setOnClickListener(this);

        SpielregelnButton = (Button) findViewById(R.id.menu_spielregeln);
        SpielregelnButton.setOnClickListener(this);

        OptionButton = (Button) findViewById(R.id.OptionenButton);
        OptionButton.setOnClickListener(this);
    }

    /**
     * OnClick-Methode der MainActivity. Switch-Abfrage welcher Button gedrückt
     * wurde. Je nach Button wird eine andere Activity gestartet.
     *
     * @param v View des Layouts
     */
    @Override
    public void onClick(View v) {

        switch (v.getId()) {

            case R.id.menu_beenden:
                finish();
                System.exit(0);
                break;

            case R.id.menu_rangliste:
                Intent ranked = new Intent(MainActivity.this, RankedActivity.class);
                startActivity(ranked);
                break;

            case R.id.menu_spielregeln:
                Intent regeln = new Intent(MainActivity.this, SpielregelnActivity.class);
                startActivity(regeln);
                break;

            case R.id.menu_start:
                Intent game = new Intent(MainActivity.this, GameActivity.class);
                startActivity(game);
                break;

            case R.id.OptionenButton:
                Intent optionen = new Intent(MainActivity.this, OptionsActivity.class);
                startActivity(optionen);
                break;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}