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

基于Google Maps实现低功耗平滑GPS车辆追踪动画方案咨询

问题描述

我正在开发一款车辆追踪应用,期望实现无跳帧的车辆平滑移动动画,以及地图随当前位置的连续移动。GPS每秒更新一次位置,无法满足流畅体验。我尝试通过插值前后两个位置,每16ms更新标记位置并移动地图以60fps过渡,实现平滑效果,但该方案在模拟器中占用70%PC CPU,功耗极高;调整至20或10fps也无明显改善。Waze应用可实现相同效果仅占用30-40%CPU,请问如何在不消耗过多设备资源的情况下达成目标?

当前高CPU占用的代码:

if(fusedLocationClient != null && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        == PackageManager.PERMISSION_GRANTED)
{
    locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            Location location = locationResult.getLastLocation();

            //Place current location marker
            LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
            if(mLastLocation == null)
            {
                mLastLocation = latLng;
                mCurrLocationMarker = Helper.setCustomMarker(MapsActivity.this, latLng, mMap);
                locationUpdater = new LocationUpdater(mMap, MapsActivity.this, mCurrLocationMarker);
            }
            mCurrLocationMarker.setRotation(calculateBearing(mLastLocation, latLng));

            //mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng,18), ANIMATION_TIME, null);
            animateMarker(mLastLocation, latLng);

            mLastLocation = latLng;
            //move map camera

        }
    };

    LocationRequest locationRequest = LocationRequest.create();
    locationRequest.setInterval(ANIMATION_TIME);
    locationRequest.setFastestInterval(ANIMATION_TIME/2);
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
} 

public void animateMarker(final LatLng startPosition, final LatLng toPosition) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();

    final long duration = ANIMATION_TIME;
    final Interpolator interpolator = new LinearInterpolator();

    handler.post(new Runnable() {
        @Override
        public void run() {
            long elapsed = SystemClock.uptimeMillis() - start;
            float t = interpolator.getInterpolation((float) elapsed
                    / duration);
            double lng = t * toPosition.longitude + (1 - t)
                    * startPosition.longitude;
            double lat = t * toPosition.latitude + (1 - t)
                    * startPosition.latitude;
            LatLng latLng = new LatLng(lat, lng);
            mCurrLocationMarker.setPosition(latLng);
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,18));

            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            }
        }
    });
}

优化方案

核心问题分析

  1. 地图重绘过度:每次插值都调用newLatLngZoom,强制地图重新计算缩放级别并完整渲染,是CPU占用过高的核心原因。
  2. 频繁对象创建:每16ms新建LatLng对象,触发频繁GC,增加CPU开销。
  3. 手动调度低效:Handler.postDelayed的固定16ms调度无法适配系统刷新率,容易产生冗余计算。
  4. GPS请求不合理:设置的更新间隔与实际GPS刷新率不匹配,导致位置回调频繁触发,叠加动画开销。

具体优化措施

1. 简化地图相机操作

使用newLatLng替代newLatLngZoom(缩放级别固定为18,无需重复计算),大幅减少地图渲染压力:

// 替换原相机移动代码
mMap.moveCamera(CameraUpdateFactory.newLatLng(tempLatLng));

2. 复用对象减少GC

全局复用LatLng对象,避免每次插值都新建实例:

// 全局变量声明
private LatLng tempLatLng = new LatLng(0, 0);

// 插值计算时复用
double lat = start.latitude + t * (end.latitude - start.latitude);
double lng = start.longitude + t * (end.longitude - start.longitude);
tempLatLng = new LatLng(lat, lng); // 若SDK不支持修改现有LatLng,用此方式复用引用

3. 用系统属性动画替代手动调度

使用ValueAnimator(Android原生属性动画框架),它会自动适配屏幕刷新率,避免冗余调度,效率远高于手动Handler:

private ValueAnimator markerAnimator;

private void startSmoothAnimation(final LatLng start, final LatLng end) {
    // 取消正在运行的动画,避免叠加
    if (markerAnimator != null && markerAnimator.isRunning()) {
        markerAnimator.cancel();
    }

    markerAnimator = ValueAnimator.ofFloat(0f, 1f);
    markerAnimator.setDuration(1000); // 与GPS每秒更新的间隔匹配
    markerAnimator.setInterpolator(new LinearInterpolator());
    
    markerAnimator.addUpdateListener(animation -> {
        float t = (float) animation.getAnimatedValue();
        double lat = start.latitude + t * (end.latitude - start.latitude);
        double lng = start.longitude + t * (end.longitude - start.longitude);
        
        tempLatLng = new LatLng(lat, lng);
        mCurrLocationMarker.setPosition(tempLatLng);
        mMap.moveCamera(CameraUpdateFactory.newLatLng(tempLatLng));
    });
    
    markerAnimator.start();
}

4. 调整GPS请求参数

匹配GPS实际刷新率,避免不必要的位置回调:

LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(1000); // GPS每秒更新一次,设置为1000ms
locationRequest.setFastestInterval(500); // 最快间隔不低于500ms,避免GPS模块过载
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

额外优化建议

  • 开启硬件加速:确保地图Activity开启硬件加速(默认开启,可在Manifest中确认):
    <activity android:name=".MapsActivity" android:hardwareAccelerated="true"/>
    
  • 简化Marker资源:使用轻量化的Marker图标(如简化SVG、小尺寸PNG),减少绘制开销。
  • 动画期间禁用交互:暂时关闭地图缩放、拖动等交互,避免额外渲染压力,动画结束后恢复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 21:57:32