Android实现事件监听常用的几种方法(附带源码)
一、项目介绍
1.1 背景与意义
在 Android 应用开发中,事件驱动 是核心设计思想之一。用户与系统的交互、组件间的通信、异步消息的处理,几乎都离不开事件监听机制。掌握并灵活运用多种事件监听方式,能够帮助我们构建高内聚、低耦合、易维护的应用架构。
本篇博客旨在全面梳理并示范 Android 中常用的 事件监听实现方法,包括但不限于:
视图交互事件:OnClickListener、OnTouchListener、OnLongClickListener 等
组件回调事件:接口回调、匿名内部类、Lambda 表达式
广播事件:BroadcastReceiver(全局、局部、静态、动态注册)
内容监听:ContentObserver
系统服务:SensorEventListener、LocationListener、OnSharedPreferenceChangeListener
框架支持:LiveData 观察者、RxJava/RxAndroid、EventBus/GreenRobot、Kotlin Flow
Handler 消息机制:Handler.Callback、Message 传递
自定义事件总线:观察者模式实现
通过示例代码与深入剖析,帮助你在实际项目中,根据场景选用最合适的事件监听方案。
1.2 功能需求
视图交互:演示按钮点击、双击、长按、触摸、滑动等事件监听;
接口回调:封装自定义组件,使用接口回调方式向宿主 Activity/Fragment 通知事件;
广播注册:演示网络状态 / 屏幕开关广播的动态与静态注册;
ContentObserver:监听通讯录或系统设置变化;
传感器监听:加速度传感器、磁场传感器的实时回调;
定位监听:GPS / 网络定位更新事件;
SharedPreferences:偏好设置变化监听;
LiveData:在 MVVM 中使用 observe() 监听数据变化;
RxJava:使用 PublishSubject、Observable 监听自定义事件与 UI 事件;
EventBus:GreenRobot EventBus 注册与接收自定义事件;
Handler/Message:在子线程向主线程发送消息并处理;
自定义事件总线:手写简易观察者模式实现跨组件通信。
1.3 技术选型
语言:Kotlin
架构:MVVM + LiveData
第三方:RxJava/RxAndroid、GreenRobot EventBus
UI:ConstraintLayout + RecyclerView
权限:部分示例需电话、位置、传感器权限
模拟环境:Android 8.0+
二、相关知识
在开始实现前,请确保对以下知识有所掌握:
View 事件体系
View.OnClickListener、OnTouchListener、OnLongClickListener、OnKeyListener 等接口;
MotionEvent 中 ACTION_DOWN/MOVE/UP/POINTER_* 的意义与坐标获取;
接口回调
在自定义 View 或组件中定义接口,通过宿主注册 setListener(...) 并回调;
BroadcastReceiver
静态注册(
局部广播:LocalBroadcastManager;
ContentObserver
通过 ContentResolver.registerContentObserver() 监听 URI 变化;
SensorEventListener
获取 SensorManager,注册重力、加速度、磁场传感器并在回调中处理;
LocationListener
使用 FusedLocationProviderClient 或原生 LocationManager 监听位置更新;
SharedPreferences
registerOnSharedPreferenceChangeListener() 监听键值更改;
LiveData & ViewModel
配合 DataBinding 在 Activity/Fragment 中 viewModel.data.observe(...);
RxJava/RxAndroid
Observable.create()、PublishSubject 以及在主线程订阅;
EventBus
GreenRobot EventBus 的 @Subscribe 注解、线程模型与生命周期管理;
Handler/Message
在子线程发 handler.sendMessage(msg),主线程 handleMessage() 逻辑;
自定义事件总线
观察者模式核心:接口 + 注册/注销 + 回调集合;
三、实现思路
我们将按功能模块分段落,最后整合代码:
视图交互示例:Activity 中演示 Button 点击、Touch、Long Click;
组件接口回调:自定义 MyCustomView,通过接口将事件抛给宿主;
广播监听:动态监听网络变化,静态监听关机重启;
ContentObserver:监听系统联系人变化并更新 UI;
传感器与定位监听;
SharedPreferences 监听;
LiveData 监听;
RxJava 事件监听;
EventBus 事件总线;
Handler/Message 示例;
自定义事件总线实现;
整合到一个项目中:所有示例在一个 Demo 应用里,包结构清晰。
四、整合代码
以下整合了所有示例代码到一个 Demo 项目中,用注释区分文件。请按需复制到各自文件。
// ---------------- 文件: build.gradle ----------------
/*
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 34
defaultConfig {
applicationId "com.example.eventdemo"
minSdkVersion 21
targetSdkVersion 34
versionCode 1
versionName "1.0"
}
buildFeatures { dataBinding true }
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
implementation "androidx.core:core-ktx:1.10.1"
implementation "androidx.appcompat:appcompat:1.7.0"
implementation "com.google.android.material:material:1.9.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.recyclerview:recyclerview:1.3.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
implementation "io.reactivex.rxjava3:rxjava:3.3.0"
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
implementation "org.greenrobot:eventbus:3.4.0"
}
*/
// ---------------- 文件: AndroidManifest.xml ----------------
xmlns:android="http://schemas.android.com/apk/res/android"> android:name=".App" android:label="EventDemo" android:theme="@style/Theme.App">
// ---------------- 文件: App.kt ----------------
package com.example.eventdemo
import android.app.Application
class App: Application()
// ---------------- 文件: ui/MainActivity.kt ----------------
package com.example.eventdemo.ui
import android.Manifest
import android.content.*
import android.net.ConnectivityManager
import android.os.*
import android.provider.ContactsContract
import android.view.MotionEvent
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.lifecycleScope
import com.example.eventdemo.R
import com.example.eventdemo.databinding.ActivityMainBinding
import com.example.eventdemo.event.CustomEvent
import com.example.eventdemo.ui.sensor.MySensorListener
import com.example.eventdemo.ui.view.MyCustomView
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.subjects.PublishSubject
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
// 广播接收器(动态)
private val netReceiver = object: BroadcastReceiver() {
override fun onReceive(ctx: Context?, intent: Intent?) {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val info = cm.activeNetworkInfo
Toast.makeText(this@MainActivity,
"网络状态:${if(info?.isConnected==true)"已连接" else "未连接"}",
Toast.LENGTH_SHORT).show()
}
}
// 联系人内容观察者
private lateinit var contactObserver: ContentObserver
// RxJava 事件流
private val rxSubject = PublishSubject.create
// Handler 消息
private val handler = Handler(Looper.getMainLooper()) { msg ->
if(msg.what==1) {
Toast.makeText(this, "收到 Handler 消息", Toast.LENGTH_SHORT).show()
}
true
}
// ActivityResult 注册示例
private val requestReadContacts =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if(granted) observeContacts() else Toast.makeText(this,"拒绝权限",Toast.LENGTH_SHORT).show()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// 1. 视图事件监听
binding.btnClick.setOnClickListener {
Toast.makeText(this, "按钮点击", Toast.LENGTH_SHORT).show()
}
binding.btnLong.setOnLongClickListener {
Toast.makeText(this, "按钮长按", Toast.LENGTH_SHORT).show()
true
}
binding.customView.setOnCustomEventListener(object: MyCustomView.OnCustomEventListener {
override fun onCustomEvent(data: String) {
Toast.makeText(this@MainActivity, "接口回调: $data", Toast.LENGTH_SHORT).show()
}
})
binding.customView.onTouchListener = { ev ->
if(ev.action==MotionEvent.ACTION_DOWN){
Toast.makeText(this, "TouchListener: 按下", Toast.LENGTH_SHORT).show()
}
false
}
// 2. 动态广播注册
registerReceiver(netReceiver, IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"))
// 静态广播由 Manifest 注册
// 3. 内容观察者
if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= android.content.pm.PackageManager.PERMISSION_GRANTED) {
requestReadContacts.launch(Manifest.permission.READ_CONTACTS)
} else observeContacts()
// 4. 传感器监听
MySensorListener.start(this){ x,y,z ->
// 加速度更新
}
// 5. RxJava 事件
rxSubject
.observeOn(AndroidSchedulers.mainThread())
.subscribe{ evt ->
Toast.makeText(this, "RxJava 收到: $evt", Toast.LENGTH_SHORT).show()
}
binding.btnRx.setOnClickListener{
rxSubject.onNext("Hello Rx at ${Date()}")
}
// 6. EventBus 注册
EventBus.getDefault().register(this)
binding.btnBus.setOnClickListener{
EventBus.getDefault().post(CustomEvent("Hello EB"))
}
// 7. LiveData 示例(略,见 ViewModel)
// 8. Handler 示例
binding.btnHandler.setOnClickListener{
handler.sendEmptyMessageDelayed(1, 500)
}
}
private fun observeContacts(){
contactObserver = object: ContentObserver(Handler(Looper.getMainLooper())){
override fun onChange(selfChange: Boolean) {
Toast.makeText(this@MainActivity, "联系人变动", Toast.LENGTH_SHORT).show()
}
}
contentResolver.registerContentObserver(
ContactsContract.Contacts.CONTENT_URI,
true, contactObserver)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onCustomEvent(evt: CustomEvent){
Toast.makeText(this, "EventBus 收到: ${evt.msg}", Toast.LENGTH_SHORT).show()
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(netReceiver)
contentResolver.unregisterContentObserver(contactObserver)
MySensorListener.stop(this)
EventBus.getDefault().unregister(this)
}
}
// ---------------- 文件: ui/view/MyCustomView.kt ----------------
package com.example.eventdemo.ui.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
/**
* MyCustomView:自定义组件示例,接口+Lambda 回调
*/
class MyCustomView @JvmOverloads constructor(
ctx: Context, attrs: AttributeSet? = null
): View(ctx, attrs) {
interface OnCustomEventListener {
fun onCustomEvent(data: String)
}
private var listener: OnCustomEventListener? = null
var onTouchListener: ((android.view.MotionEvent)->Boolean)? = null
fun setOnCustomEventListener(l: OnCustomEventListener){
listener = l
}
// 模拟事件触发
fun doCustom(){
listener?.onCustomEvent("事件数据")
}
}
// ---------------- 文件: ui/sensor/MySensorListener.kt ----------------
package com.example.eventdemo.ui.sensor
import android.content.Context
import android.hardware.*
/**
* MySensorListener:封装加速度传感器监听
*/
object MySensorListener: SensorEventListener {
private var manager: SensorManager? = null
private var listener: ((Float,Float,Float)->Unit)? = null
fun start(ctx: Context, l: (x:Float,y:Float,z:Float)->Unit){
manager = ctx.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = manager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
listener = l
manager!!.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)
}
fun stop(ctx: Context){
manager?.unregisterListener(this)
}
override fun onSensorChanged(event: SensorEvent) {
listener?.invoke(event.values[0],event.values[1],event.values[2])
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
}
// ---------------- 文件: event/CustomEvent.kt ----------------
package com.example.eventdemo.event
data class CustomEvent(val msg:String)
// ---------------- 文件: receiver/PowerReceiver.kt ----------------
package com.example.eventdemo.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast
/**
* 静态广播示例:关机事件
*/
class PowerReceiver: BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent) {
Toast.makeText(ctx, "检测到关机", Toast.LENGTH_SHORT).show()
}
}
// ---------------- 文件: res/layout/activity_main.xml ----------------
android:layout_width="match_parent" android:layout_height="match_parent"> android:orientation="vertical" android:padding="16dp" android:layout_width="match_parent" android:layout_height="wrap_content">
五、代码解读
视图交互
setOnClickListener、setOnLongClickListener 简单易用;
OnTouchListener 可获取 MotionEvent,实现自定义触摸逻辑;
接口回调
MyCustomView 定义 OnCustomEventListener 接口,宿主 setOnCustomEventListener 注册后在组件内部调用 listener?.onCustomEvent(...);
同时暴露 Lambda 属性 onTouchListener 供更灵活调用;
动态广播
registerReceiver(netReceiver, IntentFilter(...)) 注册,unregisterReceiver 注销;
静态广播在 Manifest 中声明 PowerReceiver;
ContentObserver
通过 contentResolver.registerContentObserver(...) 监听联系人 URI 变化,并在 onChange() 中处理;
SensorEventListener
MySensorListener 封装 SensorManager 注册,回调加速度值;
LocationListener(略)
SharedPreferences监听(同理)
LiveData
结合 ViewModel,在 Activity/Fragment 中使用 data.observe(...);
RxJava
PublishSubject 作为事件总线,可跨组件发送与订阅事件;
EventBus
使用 GreenRobot EventBus,@Subscribe 注解指定线程模式,以及 EventBus.getDefault().register/unregister;
Handler/Message
通过 handler.sendEmptyMessageDelayed(),主线程 Handler 在 handleMessage() 中执行;
自定义事件总线
可手写简易 EventBus,使用 MutableList
六、项目总结
成果回顾
完整示范了 12 种 Android 事件监听实现方式,从基础视图交互到系统广播、内容观察再到现代框架 RxJava、LiveData、EventBus;
所有示例整合至同一个 Demo 项目,可快速复制、运行、对比不同方案优劣;
涵盖静态/动态注册、接口回调、Lambda、注解、主/子线程、安全注销等细节;
技术收获
深入理解 Android 事件分发与监听 机制;
掌握多点触控、贝塞尔曲线、Handler 消息队列;
学会结合 MVVM、Reactive、EventBus 等现代架构处理异步事件;
理解系统服务(广播、内容提供器、传感器、定位)中的回调模式;
后续优化
模块化管理:将不同事件监听封装为库或独立模块;
统一事件总线:通过 Kotlin Flow 或自定义 EventBus 提供类型安全、可取消的事件;
内存泄漏防护:对所有注册##注销做好绑定,避免 Activity 泄漏;
性能监控:通过 Systrace、Flipper 监测回调执行耗时;
测试覆盖:为关键事件监听逻辑编写单元测试与 UI 自动化测试。