Android摇一摇

在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)

效果评价

不断使用过程中,对摇一摇的敏感度进行了多次调整,效果基本达到预期,耗电量也没有明显增加。

相关推荐
智者知已应修善业12 小时前
【4060BD_5V应用电路图】2022-12-24
驱动开发·经验分享·笔记·硬件架构·硬件工程
小李不想当小白15 小时前
DMA直接存储器存取(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·分享
2601_9653842617 小时前
口腔黏膜清洁的工程化路径:从表面形貌表征到清洁策略匹配
经验分享·笔记
泡泡鱼(敲代码中)17 小时前
Python 容器类型学习笔记:列表、元组、字典、集合
开发语言·笔记·python·pycharm
Hotchip_MEMS19 小时前
传统咪头与MEMS硅麦:雾化器气流传感方案对比
人工智能·笔记·物联网·电脑·制造
志尊宝19 小时前
Vue3 零基础每日笔记(040):Vite 创建 Vue3 + TS 项目——企业标配从这一篇开始
笔记·vue·html·前端开发·软件开发
水云桐程序员19 小时前
量子力学概论,量子力学概念总结
笔记·科技·学习·量子计算
darin_ฅ( ̳• ◡ • ̳)ฅ120 小时前
【 Obsidian】2026版-Obsidian安装Automatic Table of Contents 插件一键生成文章目录
笔记
2401_8501220420 小时前
航空、轨交、汽车线束防护有什么不同?三大行业的共性、差异与选型逻辑
经验分享·笔记·科技
志尊宝20 小时前
Vue3 零基础每日笔记(037):动手封装 useMouse 与 useWindowSize——事件监听的标准模板
前端·javascript·vue.js·笔记·html5