Android - setOnClickListener против OnClickListener против View.OnClickListener
Насколько я понимаю, когда я создаю объект кнопки, который прослушивает щелчок, я должен:
- Создать объект кнопки
- Используйте
OnClickListner
чтобы заставить его слушать щелчок пользователя - Используйте
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
}
}
Ответы
Ответ 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;
}
}