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

三星设备上React Native应用后台运行变慢的原因排查

问题背景

我开发的React Native(基于JavaScript)应用在三星Note 20 Ultra的Android系统上,前台运行状态表现正常,但切换至后台后运行速度大幅下降。应用每秒发起一次fetch API请求,新增一个返回大量数据的fetch接口后,处理该数据的循环在前台运行正常,后台时速度降至前台的1/5。

已完成排查:

  • 确认代码无任务堆积
  • 降低其他fetch请求频率无效
  • 后台无屏幕写入操作
  • 移除大数据处理逻辑后,后台运行速度与前台一致

已知React为单线程模型,但不认为这是前后台差异的原因,怀疑三星对后台应用的CPU使用做了限制,想了解具体原因及解决办法。

相关处理代码
const collectCurrentStockPrices = async (realTimeStockPriceData) => {
    console.log('Got Here');
    percentageDone = 0;
    var myCurrentTimestamp = Date.now();
    myCurrentTimestamp = myCurrentTimestamp/1000;

    for (
      realTimeStockPriceCounter = 0;
      realTimeStockPriceCounter < realTimeStockPriceData.tickers.length - 1;
      realTimeStockPriceCounter++
    ) {

      globalRealTimeStockPriceCounter = realTimeStockPriceCounter;
      realTimeStockPriceQueryArrayIndex = indexOfTicker(
        realTimeStockPriceData.tickers[realTimeStockPriceCounter].ticker,
        trackedStocks,
      );
      if (realTimeStockPriceQueryArrayIndex !== -1 && realTimeStockPriceData.tickers[realTimeStockPriceCounter].day.c !== 0 ) {
        if (Math.floor(realTimeStockPriceCounter/100) === realTimeStockPriceCounter/100) {
          percentageDone = (globalRealTimeStockPriceCounter / realTimeStockPriceData.tickers.length) * 100; 
          ReactNativeForegroundService.update({
            id: 1244,
            title: "AI Stock App",
            message: "Collecting Current Prices",
            icon: "ic_launcher",
            button: false,
            button2: false,
            buttonText: "",
            button2Text: "",
            buttonOnPress: "",
            setOnlyAlertOnce: true,
            color: "#000000",
            progress: {
              max: 100,
              curr: percentageDone,
            },
          });
        }
        if (globalDebugOn) {
          if (Math.floor(realTimeStockPriceCounter/100) === realTimeStockPriceCounter/100) {
            console.log('Processing Current Price: ' + realTimeStockPriceCounter + " " + realTimeStockPriceData.tickers[realTimeStockPriceCounter].ticker + " Value: " + realTimeStockPriceData.tickers[realTimeStockPriceCounter].day.c );
            if (AppState.currentState === 'active') {
              setDetailedStatusText('Processing Price: ' + realTimeStockPriceCounter);
            }
          }
        }
        // Use muCurrentTimestamp set above.... you want the timestamp at the 
        //    time of the query and not at the time the record was updated
        // myCurrentTimestamp = Date.now();
        // myCurrentTimestamp = (myCurrentTimestamp / 1000).toFixed(0);
        realTimeStockPriceDateToStore =
          '{ "CurrentPrice" : ' +
          realTimeStockPriceData.tickers[realTimeStockPriceCounter].day.c +
          ', "CurrentPriceTS" : ' +
          myCurrentTimestamp.toString() +
          ' }';
        try {
          realTimeJSONStockPriceData = JSON.parse(realTimeStockPriceDateToStore);
        } catch (error) {
          console.log(error);
          console.log(
            'JSON Parse 42 failed on: ' + realTimeStockPriceDateToStore,
          );
        }
        realTimeStringStockPriceData = JSON.stringify(realTimeJSONStockPriceData);
        try {
          await AsyncStorage.mergeItem(
            realTimeStockPriceData.tickers[realTimeStockPriceCounter].ticker,
            realTimeStringStockPriceData,
          );
        } catch (error) {
          console.log(error);
        }
        // Get the value back to see if it was stored correctly
        //  .... instead, lets just put it directly in storage (speeds things up)
        try {
          jsonTrackedStocksRecord = JSON.parse(trackedStocks[realTimeStockPriceQueryArrayIndex][1]);
        } catch (error) {
          console.log(error);
          console.log(
            'JSON Parse 43 failed on: ' + trackedStocks[realTimeStockPriceQueryArrayIndex][1],
          );
        }
        jsonTrackedStocksRecord.CurrentPrice = realTimeStockPriceData.tickers[realTimeStockPriceCounter].day.c;
        jsonTrackedStocksRecord.CurrentPriceTS = myCurrentTimestamp;
        trackedStocks[realTimeStockPriceQueryArrayIndex][1] = JSON.stringify(jsonTrackedStocksRecord);
        // try {
        //   realTimeStockPriceTestValue = await AsyncStorage.getItem(
        //     realTimeStockPriceData.tickers[realTimeStockPriceCounter].ticker,
        //   );
        // } catch (error) {
        //   console.log(error);
        // }
        // if (realTimeStockPriceCounter === 0 || realTimeStockPriceCounter === 1) {
        //   console.log(
        //     'Newly Written Stock Price Data: ' + realTimeStockPriceTestValue,
        //   );
        // }
        // Now update the tracked stocks in memory to reflect the changes
        //trackedStocks[realTimeStockPriceQueryArrayIndex][1] = realTimeStockPriceTestValue;
      } else {
        // if ticker in stock price record is not good
        // console.log(
        //  'Found bad ticker in stock price query: ' +
        //    stockPriceData.results[stockPriceCounter].T,
        //);
        // Delay a couple hundred milliseconds to allow other code to execute while
        //   this is in a hard loop
        await delay(200);
      }
    } // loop through stock price results for (realTimeStockPriceCounter)
    processingRealTimeStockPrices = false;
    ReactNativeForegroundService.stop({
      id: 1244,
      title: "AI Stock App",
      message: "Collecting Current Prices",
      icon: "ic_launcher"
    });
  }
原因分析
  1. 三星后台CPU限制:三星One UI系统对后台应用有严格的资源管控策略,应用切换到后台后,系统会降低其CPU优先级、限制CPU使用率,以节省电量和系统资源。大数据处理循环属于CPU密集型操作,后台时会被系统大幅限制运行速度。
  2. AsyncStorage后台性能损耗:代码中频繁调用await AsyncStorage.mergeItem,AsyncStorage的IO操作在后台时优先级也会被系统降低,叠加CPU限制后,整体处理速度进一步下降。
解决办法

1. 申请后台高优先级权限

  • 在AndroidManifest.xml中添加android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,引导用户将应用加入电池优化白名单,避免系统在后台限制应用资源。
  • 确保ReactNativeForegroundService配置正确,前台服务的CPU优先级远高于后台应用,能获得更多系统资源。

2. 优化数据处理逻辑

  • 批量处理AsyncStorage操作:将多个mergeItem请求合并为批量操作,比如使用AsyncStorage.multiMerge(若支持),减少IO次数,避免每次循环等待IO完成。
  • 简化JSON序列化/反序列化:替换手动拼接JSON字符串的逻辑,直接创建对象后序列化,减少中间步骤:
    // 优化后代码
    const realTimeJSONStockPriceData = {
      CurrentPrice: realTimeStockPriceData.tickers[realTimeStockPriceCounter].day.c,
      CurrentPriceTS: myCurrentTimestamp
    };
    const realTimeStringStockPriceData = JSON.stringify(realTimeJSONStockPriceData);
    
  • 拆分大循环:将长循环拆分为多个小任务,使用setTimeout插入非阻塞延迟,让JavaScript线程有机会释放资源,避免被系统判定为过度占用CPU:
    if (Math.floor(realTimeStockPriceCounter/100) === realTimeStockPriceCounter/100) {
      await new Promise(resolve => setTimeout(resolve, 0));
    }
    

3. 调整API请求策略

  • 降低大数据接口的请求频率:每秒一次的请求在后台过于频繁,可根据业务需求调整为每3-5秒一次,减少后台数据处理压力。
  • 请求过滤后的数据:若后端支持,只请求应用需要的ticker数据,减少前端处理的数据量,从源头降低CPU负载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 19:30:08