在APP发布后,存在用户进行错误报告的情况,如果是手动截屏通过联系方式提交一般人都不情愿,有点浪费时间。如果是摇一摇即可上传错误及前后日志文件,将大大提高用户上传问题的意愿。
实现思路
通过SensorManager的监听计算出摇动的位移区间,判断是否摇动。摇一摇的过程不存在前台UI界面,在单独的Service中实现是比较好的方案。当达到摇一摇判定的同时,发送广播通知业务层进行对应逻辑处理,如开始截屏上传和日志上传等。
实现步骤
摇一摇的工具类
主要是摇一摇的启动、停止、摇动判定和通知,代码如下
class HShakeDetector(context: Context) {
private var sensorManage: SensorManager? =
context.getSystemService(Context.SENSOR_SERVICE) as SensorManager?
private var accelerometer: Sensor? = sensorManage?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
var listener: (() -> Unit)? = null
private var lastShakeTime = 0L
private val SHAKE_INTERVAL_MS = 1000
private val sensorEventListener = object : SensorEventListener {
override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
}
override fun onSensorChanged(event: SensorEvent?) {
if (event?.sensor?.type == Sensor.TYPE_ACCELEROMETER) {
val x: Float = event.values[0] //左右方向
val y: Float = event.values[1] //前后方向
val z: Float = event.values[2] //上下方向
// Log.i("HShakeDetector", "X: $x, Y:$y, Z:$z")
val g = sqrt(x * x + y * y + z * z) - SensorManager.GRAVITY_EARTH
val threshold = 60.5 //动态阈值可根据设置调整
if (g > threshold) {
val now: Long = System.currentTimeMillis()
if (now - lastShakeTime > SHAKE_INTERVAL_MS) {
lastShakeTime = now
notifyShakeDetected()
}
}
}
}
}
fun start() {
if (accelerometer != null && listener != null) {
sensorManage?.registerListener(
sensorEventListener, accelerometer, SensorManager.SENSOR_DELAY_UI
)
}
}
fun stop() {
sensorManage?.unregisterListener(sensorEventListener)
}
private fun notifyShakeDetected() {
if (listener != null) {
val mainHandler = Handler(Looper.getMainLooper())
mainHandler.post { listener?.invoke() }
}
}
}
启动和停止
在单独的server中进行运行,记得在清单文件中进行声明。
const val H_BROADCAST_ACTION_SHAKE = "H_BROADCAST_ACTION_SHAKE" //摇一摇
class HShakeService : Service() {
private var hShake: HShakeDetector? = null
override fun onCreate() {
super.onCreate()
hShake = HShakeDetector(baseContext)
hShake?.listener = {
sendBroadcast(Intent(H_BROADCAST_ACTION_SHAKE))
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
hShake?.start()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
hShake?.stop()
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
}
<service
android:name="com.zhb.devkit.service.HShakeService"
android:exported="true" />
服务启动
在APP启动后进行服务的启动和触发事件的接收。
//启动摇一摇
startService(Intent(this, HShakeService::class.java))
registerReceiver(object : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
startActivity(Intent(this@MainActivity, HScreenCaptureActivity::class.java))
}
}, IntentFilter(H_BROADCAST_ACTION_SHAKE), RECEIVER_EXPORTED)
效果评价
不断使用过程中,对摇一摇的敏感度进行了多次调整,效果基本达到预期,耗电量也没有明显增加。