以下是如何使用Kotlin实现监控应用(客户端)死亡的步骤和代码示例。Android的DeathRecipient
接口可以让Service感知到绑定的客户端(如Activity)进程的死亡。
如何监控Application的死亡
基本原理
- 客户端(Client):通常是一个Activity,向Service传递一个
IBinder
对象。 - 服务端(Service):通过
linkToDeath
方法注册一个DeathRecipient
,当客户端进程死亡时,Service会收到通知。 - 死亡通知:当客户端被杀死(例如通过
adb shell kill <pid>
),DeathRecipient
的binderDied()
方法会被调用。
实现步骤
- 定义AIDL接口(用于Client和Service之间的通信)。
- 在客户端中创建一个
Binder
对象并传递给Service。 - 在Service中实现
DeathRecipient
,并通过linkToDeath
监控客户端的死亡。 - 测试:启动应用,绑定Service,杀死客户端进程,观察日志。
Kotlin实现代码
1. 定义AIDL接口(ITest.aidl)
创建一个名为ITest.aidl
的文件,路径为app/src/main/aidl/com/example/testservice/ITest.aidl
:
package com.example.testservice;
interface ITest {
int getPid();
void setBinder(IBinder client);
}
2. 客户端实现(MainActivity.kt)
package com.example.testservice
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.example.testservice.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val TAG = "TestService"
private lateinit var binding: ActivityMainBinding
private val intent = Intent("com.example.action.TEST").apply {
setPackage(packageName) // 确保绑定到正确的Service
}
private val binder = object : android.os.Binder() {} // 客户端的Binder对象
private var testService: ITest? = null
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d(TAG, "onServiceConnected: $name")
testService = ITest.Stub.asInterface(service)
try {
testService?.setBinder(binder) // 传递Binder给Service
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(TAG, "onServiceDisconnected")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 按钮点击事件
binding.start.setOnClickListener { startService(intent) }
binding.stop.setOnClickListener { stopService(intent) }
binding.bind.setOnClickListener { bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) }
binding.unbind.setOnClickListener { unbindService(serviceConnection) }
}
}
3. 服务端实现(TestService.kt)
package com.example.testservice
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
class TestService : Service() {
private val TAG = "TestService"
private val testApi = TestApi()
private var clientBinder: IBinder? = null
override fun onBind(intent: Intent?): IBinder {
Log.d(TAG, "onBind() action=${intent?.action}")
return testApi
}
// DeathRecipient实现
private inner class TestDeathRecipient : IBinder.DeathRecipient {
override fun binderDied() {
Log.d(TAG, "客户端已死亡")
clientBinder = null // 清理引用
}
}
// AIDL接口实现
private inner class TestApi : ITest.Stub() {
override fun getPid(): Int {
return Thread.currentThread().id.toInt()
}
override fun setBinder(client: IBinder?) {
clientBinder = client
clientBinder?.linkToDeath(TestDeathRecipient(), 0) // 注册死亡通知
}
}
}
4. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testservice">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".TestService"
android:process=":service">
<intent-filter>
<action android:name="com.example.action.TEST" />
</intent-filter>
</service>
</application>
</manifest>
5. 布局文件(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/start"
android:text="Stop" />
<Button
android:id="@+id/bind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/start"
android:text="Bind" />
<Button
android:id="@+id/unbind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/stop"
android:layout_toRightOf="@id/bind"
android:text="Unbind" />
</RelativeLayout>
测试步骤
- 启动应用,点击“Start”按钮启动Service。
- 点击“Bind”按钮绑定Service。
- 使用
adb shell ps | grep com.example.testservice
找到客户端进程的PID。 - 使用
adb shell kill <pid>
杀死客户端进程。 - 检查Logcat,观察是否打印出
"客户端已死亡"
日志。