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

Wear OS后台加速度计响应获取及持续跌倒检测服务实现咨询

解决Wear OS上跌倒检测后台服务持续运行的问题

首先,你的核心问题在于IntentService已经不适合Android 8.0+(包括Wear OS)的后台运行场景——系统对后台服务有严格的限制,IntentService完成任务后会自动销毁,而且非前台的后台服务在闲置1-2分钟左右就会被系统回收。要实现持续的跌倒检测,我们需要改用Foreground Service,并结合Wear OS的特性做针对性优化。

关键解决方案步骤

1. 替换IntentService为Foreground Service

Foreground Service会在手表的通知中心显示一个持续的通知,以此获得更高的系统优先级,避免被轻易杀死。这是后台长期运行服务的必要条件,Wear OS对前台服务的优先级保护比普通Android设备更严格。

2. 适配Wear OS的通知要求

Wear OS对前台服务的通知有硬性要求:必须设置小图标,否则服务无法启动。同时通知内容要简洁,适配手表的小屏幕尺寸。

3. 优化传感器监听逻辑

  • 避免重复初始化传感器和检测算法(你的原代码在onCreate和onStartCommand中都做了初始化,会导致资源浪费和重复注册)。
  • 选择合适的传感器采样率(比如SensorManager.SENSOR_DELAY_NORMAL),平衡检测精度和功耗,低功耗能减少系统回收服务的概率。

4. 申请电池优化豁免

引导用户将应用加入电池优化白名单,避免低功耗模式下服务被系统强制暂停。

修改后的完整代码示例

public class FallDetectService extends Service implements SensorEventListener {
    private static final String TAG = "FallDetectService";
    private static final int FOREGROUND_NOTIFICATION_ID = 1001;
    private SensorManager sensorManager;
    private Sensor accelerometer;
    private FallDetectAlgo fallDetectAlgo;
    private boolean flag_fall = false;
    private boolean f_send_msg = true;
    private SharedPreferences sharedPreferences;
    private String watch_id;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Service created");
        sharedPreferences = getApplicationContext().getSharedPreferences("USER", MODE_PRIVATE);
        watch_id = sharedPreferences.getString("key_watch_id", "");
        
        // 仅初始化一次跌倒检测算法
        fallDetectAlgo = new FallDetectAlgo();
        fallDetectAlgo.setDaemon(true);
        fallDetectAlgo.start();
        
        // 初始化传感器管理器
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 启动前台服务,显示适配Wear OS的通知
        startForeground(FOREGROUND_NOTIFICATION_ID, createForegroundNotification());
        
        // 注册传感器监听(确保仅注册一次)
        if (accelerometer != null) {
            sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
        } else {
            Toast.makeText(this, "No Accelerometer Found!!", Toast.LENGTH_LONG).show();
            stopSelf();
        }
        
        // 使用START_STICKY,服务被系统杀死后会尝试自动重启
        return START_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null; // 不需要绑定服务时返回null即可
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        boolean bufferReady = fallDetectAlgo.get_buffer_ready();
        if (!bufferReady) {
            return;
        }
        
        flag_fall = fallDetectAlgo.set_data(event);
        if (flag_fall) {
            if (f_send_msg) {
                f_send_msg = false;
                Log.i(TAG, "Fall detected successfully!");
                fallEventOccured();
            }
        } else {
            f_send_msg = true;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // 忽略传感器精度变化
    }

    private Notification createForegroundNotification() {
        // 创建Wear OS适配的通知通道(Android 8.0+必须)
        String channelId = "fall_detection_channel";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    channelId,
                    "Fall Detection",
                    NotificationManager.IMPORTANCE_LOW // 低优先级,避免打扰用户
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }

        // 构建适合手表的通知内容
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_watch_fallback) // 必须设置小图标,Wear OS强制要求
                .setContentTitle("Fall Detection Active")
                .setContentText("Monitoring for falls...")
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setVisibility(NotificationCompat.VISIBILITY_SECRET); // 手表上隐藏敏感内容(可选)

        return builder.build();
    }

    private void fallEventOccured() {
        StringRequest stringRequest = new StringRequest(Request.Method.POST, "YOUR_FALL_EVENT_API_URL",
                response -> Log.e("fallEventOccured", "API Response: " + response),
                error -> {
                    Log.e("fallEventOccured", "API Error: " + error);
                    Toast.makeText(getApplicationContext(), "Please try later", Toast.LENGTH_SHORT).show();
                }) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> params = new HashMap<>();
                params.put("watch_id", watch_id);
                return params;
            }
        };

        stringRequest.setRetryPolicy(new DefaultRetryPolicy(
                0,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        VolleySingleton.getInstance(this).addToRequestQueue(stringRequest);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "Service destroyed");
        // 注销传感器监听,避免内存泄漏
        if (sensorManager != null) {
            sensorManager.unregisterListener(this);
        }
    }
}

额外配置与注意事项

  • 权限声明:在AndroidManifest.xml中添加必要权限:

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    
  • 申请电池优化豁免:在启动服务前,检查并引导用户添加白名单:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (!pm.isIgnoringBatteryOptimizations(getPackageName())) {
            Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + getPackageName()));
            startActivity(intent);
        }
    }
    
  • Wear OS低功耗模式适配:如果用户开启了手表省电模式,即使是前台服务也可能被限制。可以考虑结合Wear OS的WearableListenerService在低功耗模式下触发检测,但这会增加复杂度,建议优先保证前台服务的稳定性。

内容的提问来源于stack exchange,提问作者SurajSingh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 17:37:56