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
相关产品推荐
相关产品推荐

