Android 中的事件处理
当用户在应用界面上执行各种操作时, 应用程序需要为用户的动作提供响应, 这种响应的过程就是事件处理.
事件处理:
1. 基于监听的事件处理机制.
2. 基于回调的事件处理机制.
1. 基于监听的事件处理机制
监听三要素:
- Event Source (事件源)
- Event (事件)
- Event Listener (事件监听器)
实现监听事件的方法:
- 通过内部类实现.
- 通过匿名内部类实现.
- 通过事件源所在类实现.
- 通过外部类实现.
- 布局文件中 OnClick 属性 (针对点击事件).
通过内部类实现
package com.example.hello;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.example.hello.util.ToastUtil;
public class EventActivity extends AppCompatActivity {
private Button btnEvent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
btnEvent = findViewById(R.id.btn_event);
// 通过内部类实现
btnEvent.setOnClickListener(new OnClick());
}
class OnClick implements View.OnClickListener {
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_event:
ToastUtil.showShortToast(EventActivity.this, "通过内部类实现");
break;
default:
throw new IllegalStateException("Unexpected value: " + v.getId());
}
}
}
}
通过匿名内部类实现
package com.example.hello;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import com.example.hello.util.ToastUtil;
public class EventActivity extends AppCompatActivity {
private Button btnEvent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
btnEvent = findViewById(R.id.btn_event);
// 通过匿名内部类实现
btnEvent.setOnClickListener(v -> {
ToastUtil.showShortToast(EventActivity.this, "通过匿名内部类实现");
});
}
}
通过事件源所在类实现
package com.example.hello;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.example.hello.util.ToastUtil;
public class EventActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnEvent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
btnEvent = findViewById(R.id.btn_event);
}
/**
* 通过事件源所在类实现
*
* @param v view
*/
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_event:
ToastUtil.showShortToast(EventActivity.this, "通过事件源所在类实现");
break;
default:
throw new IllegalStateException("Unexpected value: " + v.getId());
}
}
}
通过外部类实现
先建立一个类
package com.example.hello.util;
import android.app.Activity;
import android.view.View;
public class EventUtil implements View.OnClickListener {
private Activity activity;
private String content;
public EventUtil(Activity activity, String content) {
this.activity = activity;
this.content = content;
}
@Override
public void onClick(View v) {
ToastUtil.showShortToast(activity, content);
}
}
package com.example.hello;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import com.example.hello.util.EventUtil;
public class EventActivity extends AppCompatActivity {
private Button btnEvent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
btnEvent = findViewById(R.id.btn_event);
// 通过外部类实现
btnEvent.setOnClickListener(new EventUtil(EventActivity.this, "通过外部类实现"));
}
}
布局文件中 OnClick 属性 (针对点击事件)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".EventActivity">
<Button
android:id="@+id/btn_event"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showEvent"
android:text="@string/event" />
</LinearLayout>
package com.example.hello;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import com.example.hello.util.ToastUtil;
public class EventActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
}
/**
* 布局文件中 OnClick 属性 (针对点击事件)
*
* @param view v
*/
@SuppressLint("NonConstantResourceId")
public void showEvent(View view) {
switch (view.getId()) {
case R.id.btn_event:
ToastUtil.showShortToast(EventActivity.this, "布局文件中 OnClick 属性 (针对点击事件)");
break;
default:
throw new IllegalStateException("Unexpected value: " + view.getId());
}
}
}
这几种方法中没有优先级的概念, 哪一个是最后设置就只执行哪一个. 其中布局的方法是最先加载的, 所以是最先设置的.
2. 基于回调的事件处理机制
回调机制与监听机制的区别: 回调机制中事件源与事件监听是绑在一起的.
基于事件的传播.
自定义一个 Button
package com.example.hello.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import androidx.appcompat.widget.AppCompatButton;
public class MyButton extends AppCompatButton {
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("MyButton", "---onTouchEvent:ACTION_DOWN---");
break;
case MotionEvent.ACTION_UP:
Log.d("MyButton", "---onTouchEvent:ACTION_UP---");
break;
}
return false;
}
}
在布局中添加 MyButton
<com.example.hello.widget.MyButton
android:id="@+id/btn_myButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/event" />
EventActivity 设置 MyButton.
package com.example.hello;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import com.example.hello.widget.MyButton;
public class EventActivity extends AppCompatActivity {
private MyButton myButton;
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
myButton = findViewById(R.id.btn_myButton);
myButton.setOnTouchListener((v, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("EventActivityListener", "---onTouchEvent:ACTION_DOWN---");
break;
}
return false;
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("EventActivity", "---onTouchEvent:ACTION_DOWN---");
break;
}
return false;
}
}
从日志打印可以看出监听优于回调.
return false; 代表继续向外传播.
return true; 代表停止向外传播.