Android Studio中满足加速度阈值时延迟发送通知的实现方法
需求与问题
我正在开发一款Android应用,需求是:当手机加速度累计值超过设定阈值(如1000)时,延迟发送通知。目前已完成:通过加速度传感器计算加速度变化值并累加得到总数值,实现了按钮点击触发通知的功能。这是我首次用Android Studio和Java开发,求满足条件触发延迟通知的实现方案。
我的Activity代码如下:
public class calibration extends AppCompatActivity { TextView txt_currentAccel, txt_prevAccel, txt_acceleration; TextView txt_totalAccel; ProgressBar prog_shakeMeter; private SensorManager mSensorManager; private Sensor mAccelerometer; private double accelerationPreviousValue; private double accelerationTotalValue; Button notifyBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.calibration_layout); // get layout ID's acceleration txt_acceleration = findViewById(R.id.txt_accel); txt_prevAccel = findViewById(R.id.txt_prevAccel); txt_currentAccel = findViewById(R.id.txt_currentAccel); txt_totalAccel = findViewById(R.id.txt_totalAccel); prog_shakeMeter = findViewById(R.id.prog_shakeMeter); // get info sensors mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // notification // open main page when clicking on notification Intent resultIntent = new Intent(this, MainActivity.class); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addNextIntentWithParentStack(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // find button to activate notification notifyBtn = findViewById(R.id.Notification_Button); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("My Notification","My Notification", NotificationManager.IMPORTANCE_DEFAULT); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } notifyBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { NotificationCompat.Builder builder = new NotificationCompat.Builder(calibration.this,"My Notification"); builder.setContentTitle("My Title"); builder.setContentText("This is a simple notification"); builder.setSmallIcon(R.mipmap.ic_launcher_foreground); builder.setAutoCancel(true); builder.setPriority(NotificationCompat.PRIORITY_HIGH); builder.setContentIntent(resultPendingIntent); NotificationManagerCompat managerCompat = NotificationManagerCompat.from(calibration.this); managerCompat.notify(1,builder.build()); } }); } // calculation acceleration private final SensorEventListener sensorEventListener = new SensorEventListener() { @SuppressLint("SetTextI18n") @Override public void onSensorChanged(SensorEvent sensorEvent) { float x = sensorEvent.values[0]; float y = sensorEvent.values[1]; float z = sensorEvent.values[2]; double accelerationCurrentValue = Math.sqrt((x * x + y * y + z * z)); double changeIntAcceleration = Math.abs(accelerationCurrentValue - accelerationPreviousValue); accelerationPreviousValue = accelerationCurrentValue; accelerationTotalValue = accelerationTotalValue + changeIntAcceleration; txt_currentAccel.setText("Current = "+ accelerationCurrentValue); txt_prevAccel.setText("Prev = "+ accelerationCurrentValue); txt_acceleration.setText("Acceleration change = "+ changeIntAcceleration); txt_totalAccel.setText("Total = "+ accelerationTotalValue); prog_shakeMeter.setProgress((int)changeIntAcceleration); } @Override public void onAccuracyChanged(Sensor sensor, int i) { } }; protected void onResume() { super.onResume(); mSensorManager.registerListener(sensorEventListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); } protected void onPause() { super.onPause(); mSensorManager.unregisterListener(sensorEventListener); } }
实现方案
以下是满足需求的具体实现步骤:
1. 定义核心常量与控制标记
添加阈值、延迟时间常量,以及防止重复触发的标记:
// 加速度累计阈值 private static final double ACCELERATION_THRESHOLD = 1000.0; // 延迟通知时间(毫秒,示例为5秒) private static final long NOTIFICATION_DELAY = 5000; // 标记是否已触发延迟通知,避免重复执行 private boolean isNotificationPending = false; // 用于实现延迟的Handler private Handler notificationHandler = new Handler(Looper.getMainLooper());
2. 重构通知代码为独立方法
把按钮点击里的通知逻辑抽成单独方法,方便复用:
private void sendNotification() { Intent resultIntent = new Intent(this, MainActivity.class); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addNextIntentWithParentStack(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); NotificationCompat.Builder builder = new NotificationCompat.Builder(calibration.this,"My Notification"); builder.setContentTitle("加速度阈值触发"); builder.setContentText("累计加速度已超过设定阈值"); builder.setSmallIcon(R.mipmap.ic_launcher_foreground); builder.setAutoCancel(true); builder.setPriority(NotificationCompat.PRIORITY_HIGH); builder.setContentIntent(resultPendingIntent); NotificationManagerCompat managerCompat = NotificationManagerCompat.from(calibration.this); managerCompat.notify(1,builder.build()); // 发送后重置标记,允许下次触发 isNotificationPending = false; }
3. 在传感器回调中添加阈值判断与延迟触发逻辑
修改onSensorChanged方法,当累计值超过阈值且未触发过延迟时,启动Handler延迟执行通知:
@SuppressLint("SetTextI18n") @Override public void onSensorChanged(SensorEvent sensorEvent) { float x = sensorEvent.values[0]; float y = sensorEvent.values[1]; float z = sensorEvent.values[2]; double accelerationCurrentValue = Math.sqrt((x * x + y * y + z * z)); double changeIntAcceleration = Math.abs(accelerationCurrentValue - accelerationPreviousValue); accelerationPreviousValue = accelerationCurrentValue; accelerationTotalValue = accelerationTotalValue + changeIntAcceleration; txt_currentAccel.setText("Current = "+ accelerationCurrentValue); txt_prevAccel.setText("Prev = "+ accelerationPreviousValue); // 修正原代码的赋值bug txt_acceleration.setText("Acceleration change = "+ changeIntAcceleration); txt_totalAccel.setText("Total = "+ accelerationTotalValue); prog_shakeMeter.setProgress((int)changeIntAcceleration); // 判断是否达到阈值且未触发延迟通知 if (accelerationTotalValue >= ACCELERATION_THRESHOLD && !isNotificationPending) { isNotificationPending = true; // 延迟指定时间后发送通知 notificationHandler.postDelayed(new Runnable() { @Override public void run() { sendNotification(); } }, NOTIFICATION_DELAY); } }
4. 页面销毁时清理Handler任务
在onDestroy方法中移除未执行的Handler任务,避免内存泄漏:
@Override protected void onDestroy() { super.onDestroy(); notificationHandler.removeCallbacksAndMessages(null); }
完整修改后的代码
public class calibration extends AppCompatActivity { TextView txt_currentAccel, txt_prevAccel, txt_acceleration; TextView txt_totalAccel; ProgressBar prog_shakeMeter; private SensorManager mSensorManager; private Sensor mAccelerometer; private double accelerationPreviousValue; private double accelerationTotalValue; Button notifyBtn; // 核心常量与控制标记 private static final double ACCELERATION_THRESHOLD = 1000.0; private static final long NOTIFICATION_DELAY = 5000; private boolean isNotificationPending = false; private Handler notificationHandler = new Handler(Looper.getMainLooper()); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.calibration_layout); // 获取控件ID txt_acceleration = findViewById(R.id.txt_accel); txt_prevAccel = findViewById(R.id.txt_prevAccel); txt_currentAccel = findViewById(R.id.txt_currentAccel); txt_totalAccel = findViewById(R.id.txt_totalAccel); prog_shakeMeter = findViewById(R.id.prog_shakeMeter); // 初始化传感器 mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // 创建通知渠道(仅Android 8.0+需要) if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("My Notification","My Notification", NotificationManager.IMPORTANCE_DEFAULT); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } // 按钮触发通知(保留原功能) notifyBtn = findViewById(R.id.Notification_Button); notifyBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { sendNotification(); } }); } // 发送通知的独立方法 private void sendNotification() { Intent resultIntent = new Intent(this, MainActivity.class); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addNextIntentWithParentStack(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); NotificationCompat.Builder builder = new NotificationCompat.Builder(calibration.this,"My Notification"); builder.setContentTitle("加速度阈值触发"); builder.setContentText("累计加速度已超过设定阈值"); builder.setSmallIcon(R.mipmap.ic_launcher_foreground); builder.setAutoCancel(true); builder.setPriority(NotificationCompat.PRIORITY_HIGH); builder.setContentIntent(resultPendingIntent); NotificationManagerCompat managerCompat = NotificationManagerCompat.from(calibration.this); managerCompat.notify(1,builder.build()); isNotificationPending = false; } // 传感器事件回调 private final SensorEventListener sensorEventListener = new SensorEventListener() { @SuppressLint("SetTextI18n") @Override public void onSensorChanged(SensorEvent sensorEvent) { float x = sensorEvent.values[0]; float y = sensorEvent.values[1]; float z = sensorEvent.values[2]; double accelerationCurrentValue = Math.sqrt((x * x + y * y + z * z)); double changeIntAcceleration = Math.abs(accelerationCurrentValue - accelerationPreviousValue); accelerationPreviousValue = accelerationCurrentValue; accelerationTotalValue = accelerationTotalValue + changeIntAcceleration; // 更新UI显示 txt_currentAccel.setText("Current = "+ accelerationCurrentValue); txt_prevAccel.setText("Prev = "+ accelerationPreviousValue); txt_acceleration.setText("Acceleration change = "+ changeIntAcceleration); txt_totalAccel.setText("Total = "+ accelerationTotalValue); prog_shakeMeter.setProgress((int)changeIntAcceleration); // 阈值判断与延迟触发 if (accelerationTotalValue >= ACCELERATION_THRESHOLD && !isNotificationPending) { isNotificationPending = true; notificationHandler.postDelayed(new Runnable() { @Override public void run() { sendNotification(); } }, NOTIFICATION_DELAY); } } @Override public void onAccuracyChanged(Sensor sensor, int i) {} }; @Override protected void onResume() { super.onResume(); mSensorManager.registerListener(sensorEventListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(sensorEventListener); } @Override protected void onDestroy() { super.onDestroy(); notificationHandler.removeCallbacksAndMessages(null); } }
注意事项
- 原代码中
txt_prevAccel的赋值存在bug,已修正为使用accelerationPreviousValue - 如果需要在应用后台也能检测加速度并触发通知,需要使用前台服务,因为后台Activity会被系统限制传感器访问
Handler仅适用于Activity存活期间的延迟任务,若要实现跨进程/重启后的延迟,需改用AlarmManager
内容的提问来源于stack exchange,提问作者quinten
相关产品推荐
相关产品推荐

