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

Expo React Native计步器代码在Android设备无步数显示问题求助

Expo React Native计步器无法显示步数问题修复

问题背景

使用Expo React Native开发计步器页面,代码无语法错误,设备满足硬件要求,但步数始终无法正常显示。核心逻辑是通过subscribe函数检测设备计步器支持状态,读取步数并更新stepCount变量。

原代码

import React, { useEffect, useState } from 'react';

import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { Pedometer } from "expo-sensors";
import { StatusBar } from "expo-status-bar";
import {
    StyleSheet,
    Text,
    View,
    ImageBackground,
    Dimensions,
} from "react-native";
import { LinearGradient } from 'expo-linear-gradient';
import LottieView from 'lottie-react-native';
import CircularProgress from "react-native-circular-progress-indicator";
import styles from '../styles';

export default function StepCounter({ navigation }) {
  const [pedometerAvailability, setPedometerAvailability] = useState('');
  const [stepCount, setStepCount] = useState(0);

  const WindowHeight = Dimensions.get('window').height;

  const Distokm = 1000 / 1250;
  const Dist = 1800 / 1300;
  const DistanceCovered = Dist.toFixed(4);

  const cal = DistanceCovered * 60;
  const caloriesBurnt = cal.toFixed(4);

  useEffect(() => {
    subscribe();
    resetStepCountDaily();
  }, []);

  const resetStepCountDaily = () => {
    const now = new Date();
    const nextDay = new Date(
      now.getFullYear(),
      now.getMonth(),
      now.getDate() + 1,
    );
    const timeUntilNextDay = nextDay.getTime() - now.getTime();

    setTimeout(() => {
      setStepCount(500);
      resetStepCountDaily();
    }, timeUntilNextDay);
  };

  const subscribe = () => {
    const subscription = Pedometer.watchStepCount((result) => {
      setStepCount(result.steps);
    });

    Pedometer.isAvailableAsync().then(
      (result) => {
        setPedometerAvailability(String(result));
      },
      (error) => {
        setPedometerAvailability(error);
      },
    );
  };

  // Loading Custom Fonts
  let [fontsLoaded] = useFonts({
    orbitron: require('../assets/fonts/Orbitron.ttf'),
    orbitron_bold: require('../assets/fonts/static/Orbitron-Bold.ttf'),,
  });

  if (!fontsLoaded) {
    return <AppLoading />;
  }
  return (
    <ImageBackground
      style={styles.homecontainer}
      source={require('../assets/night2.jpg')}
      resizeMode="cover">
      <View style={styles.pedoheader}>
        <Text style={styles.pedotext}>
          Pedometer Availability : {pedometerAvailability}
        </Text>
        <Text style={styles.pedotext}>Steps : {stepCount}</Text>
      </View>
      <View style={styles.counterview}>
        <CircularProgress
          value={stepCount}
          maxValue={1800}
          radius={150}
          progressValueColor={'#fff'}
          strokeColorConfig={[
            { color: 'red', value: 0 },
            { color: 'skyblue', value: 500 },
            { color: 'yellowgreen', value: 1500 },
            { color: 'green', value: 1800 },
          ]}
          color={'#FFFFFF'}
          circleBackgroundColor="#CAD5E2"
          inActiveStrokeOpacity={0.5}
          inActiveStrokeWidth={35}
          activeStrokeWidth={35}
          title={'Step Count'}
          titleColor={'#ecf0f1'}
          titleStyle={{ fontFamily: 'orbitron_bold', fontSize: 25 }}
        />
      </View>

      <View style={styles.counterview}>
        <LottieView
          autoPlay
          style={styles.loginlottie}
          source={require('../assets/lottie/walk1.json')}
        />
      </View>
    </ImageBackground>
  );
}

问题排查与修复方案

1. 修复字体加载语法错误

原代码中orbitron_bold的require语句后多了一个逗号,导致潜在语法问题:

// 错误写法
orbitron_bold: require('../assets/fonts/static/Orbitron-Bold.ttf'),,

// 修正后
orbitron_bold: require('../assets/fonts/static/Orbitron-Bold.ttf'),

2. 处理计步器订阅生命周期

watchStepCount返回的订阅未在组件卸载时清理,可能导致内存泄漏或异常。修改useEffect添加清理逻辑:

useEffect(() => {
  let stepSubscription;
  let resetTimeoutId;

  const subscribe = async () => {
    // 先检测计步器可用性
    const isAvailable = await Pedometer.isAvailableAsync();
    setPedometerAvailability(String(isAvailable));
    if (!isAvailable) return;

    // 监听步数变化
    stepSubscription = Pedometer.watchStepCount((result) => {
      setStepCount(result.steps);
    });
  };

  const resetStepCountDaily = () => {
    const now = new Date();
    const nextDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
    const timeUntilNextDay = nextDay.getTime() - now.getTime();

    resetTimeoutId = setTimeout(() => {
      setStepCount(0); // 重置为0而非500,符合实际需求
      resetStepCountDaily();
    }, timeUntilNextDay);
    return resetTimeoutId;
  };

  subscribe();
  resetTimeoutId = resetStepCountDaily();

  // 组件卸载时清理订阅和定时器
  return () => {
    if (stepSubscription) stepSubscription.remove();
    if (resetTimeoutId) clearTimeout(resetTimeoutId);
  };
}, []);

3. 正确获取当日累计步数

watchStepCount返回的是从监听开始的累计步数,而非设备当日总步数。添加函数获取当日已走步数:

// 获取当日步数的函数
const getTodaySteps = async () => {
  const startOfDay = new Date();
  startOfDay.setHours(0, 0, 0, 0);
  const endOfDay = new Date();
  
  try {
    const result = await Pedometer.getStepCountAsync(startOfDay, endOfDay);
    setStepCount(result.steps);
  } catch (err) {
    console.error('获取当日步数失败:', err);
  }
};

// 在subscribe中调用,结合实时监听
const subscribe = async () => {
  const isAvailable = await Pedometer.isAvailableAsync();
  setPedometerAvailability(String(isAvailable));
  if (!isAvailable) return;

  // 先获取当日已走步数
  await getTodaySteps();

  // 监听实时步数更新
  stepSubscription = Pedometer.watchStepCount((result) => {
    setStepCount(result.steps);
  });
};

4. 配置必要权限

确保在app.json中添加计步器相关权限,否则设备会拒绝访问运动数据:

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSMotionUsageDescription": "需要访问您的运动数据来统计每日步数"
      }
    },
    "android": {
      "permissions": ["ACTIVITY_RECOGNITION"]
    }
  }
}

5. 修正每日重置逻辑

原代码重置步数为500不符合实际需求,改为重置为0,并可选择重置后重新获取当日步数:

const resetStepCountDaily = () => {
  const now = new Date();
  const nextDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
  const timeUntilNextDay = nextDay.getTime() - now.getTime();

  resetTimeoutId = setTimeout(() => {
    setStepCount(0);
    // 可选:重置后重新获取当日步数
    // getTodaySteps();
    resetStepCountDaily();
  }, timeUntilNextDay);
  return resetTimeoutId;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 05:37:29