You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:30:55