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

安卓Google Maps DirectionsAPI路线更新流畅度优化求助

实时路线更新卡顿优化方案

问题背景

基于Google Maps API开发Android应用,已实现getPlaceDetails、getDirections、drawRouteOnMap等功能,目标是实现类似Waze的实时路线更新:用户移动时自动删除旧路线并绘制新路线。当前在startLocationUpdates()中设置用户移动超过10米时调用getDirections()更新路线,但主线程频繁出现帧丢失(如“Skipped 33 frames!”),应用卡顿,尝试AsyncTask、Handler优化未解决。

核心卡顿原因

  • getDirections()同步阻塞主线程:使用request.await()同步调用Google Directions API,阻塞主线程直到API返回结果,直接导致UI卡顿。
  • GeoApiContext重复创建:每次调用getDirections()都新建上下文对象,造成不必要的资源开销。
  • 位置更新触发过于频繁:10米的更新阈值会导致短时间内多次发起路线请求,加重主线程负担。
  • 路线解码与绘制未异步处理:路线polyline解码和地图绘制操作直接在主线程执行,占用UI线程资源。
  • Firebase操作阻塞主线程:位置回调中的GeoFire位置更新属于IO操作,直接在主线程执行会拖慢UI响应。

优化方案

1. 异步执行Directions API请求,避免阻塞主线程

将同步调用改为异步回调,复用全局GeoApiContext,并将路线解码逻辑放到后台线程执行,仅在主线程更新地图。

// 全局复用GeoApiContext,在Activity onCreate中初始化一次
private GeoApiContext geoApiContext;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...其他初始化代码
    geoApiContext = new GeoApiContext.Builder()
            .apiKey("YOUR_API_KEY")
            .build();
}

private void getDirections(LatLng origin, LatLng destination){
    DirectionsApiRequest request = DirectionsApi.getDirections(geoApiContext,
            String.format("%f,%f", origin.latitude, origin.longitude),
            String.format("%f,%f", destination.latitude, destination.longitude));

    // 异步请求,避免阻塞主线程
    request.setCallback(new com.google.maps.PendingResult.Callback<DirectionsResult>() {
        @Override
        public void onResult(DirectionsResult result) {
            // 后台线程解码路线polyline
            new Thread(() -> {
                List<LatLng> path = decodeRoutePolyline(result.routes[0]);
                // 切换到主线程更新地图
                runOnUiThread(() -> drawRouteOnMap(path));
            }).start();
        }

        @Override
        public void onFailure(Throwable e) {
            e.printStackTrace();
        }
    });
}

// 提取路线解码逻辑,在后台线程执行
private List<LatLng> decodeRoutePolyline(DirectionsRoute route) {
    List<LatLng> path = new ArrayList<>();
    for (DirectionsLeg leg : route.legs) {
        for (DirectionsStep step : leg.steps) {
            EncodedPolyline polyline = step.polyline;
            List<com.google.maps.model.LatLng> decodedPolyline = polyline.decodePath();
            for (com.google.maps.model.LatLng point : decodedPolyline) {
                path.add(new LatLng(point.lat, point.lng));
            }
        }
    }
    return path;
}

// 修改绘制逻辑,直接接收解码后的路径
private void drawRouteOnMap(List<LatLng> path) {
    if(currentPolyLine == null){
        currentPolyLine = mMap.addPolyline(new PolylineOptions()
                .color(Color.GREEN)
                .width(10));
    }
    currentPolyLine.setPoints(path); // 复用Polyline对象,直接更新点集
}

2. 调整位置更新阈值与频率

  • 提高路线更新的距离阈值,减少不必要的API请求;
  • 优化LocationRequest参数,降低位置更新频率,同时限制最快更新间隔。
private void startLocationUpdates() {
    // ...其他代码
    LocationRequest locationRequest = new LocationRequest();
    locationRequest.setInterval(10000); // 基础更新间隔10秒
    locationRequest.setFastestInterval(5000); // 最快更新间隔5秒,避免过于频繁
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    // ...其他代码

    // 调整路线更新距离阈值
    float distance = prevLocation.distanceTo(smoothLocate);
    if(distance >= 25){ // 改为25米更新一次路线
        prevLocation=smoothLocate;
        if(destinationLocation!=null){
            getDirections(userL,destinationLocation);
        }
    }
}

3. 分离位置平滑与距离判断的历史位置

避免prevLocation同时用于位置平滑和距离判断,单独维护平滑用的历史位置,减少逻辑混淆。

private Location smoothLocationHistory; // 专门用于位置平滑的历史位置

private Location smoothLocationUpdate(Location newLocation) {
    if (smoothLocationHistory == null) {
        smoothLocationHistory = newLocation;
        return newLocation;
    }

    double weight = 0.7; // 调整权重,减少过度平滑导致的位置延迟
    double lat = smoothLocationHistory.getLatitude() + weight * (newLocation.getLatitude() - smoothLocationHistory.getLatitude());
    double lng = smoothLocationHistory.getLongitude() + weight * (newLocation.getLongitude() - smoothLocationHistory.getLongitude());

    Location smoothedLocation = new Location(newLocation);
    smoothedLocation.setLatitude(lat);
    smoothedLocation.setLongitude(lng);
    smoothLocationHistory = smoothedLocation;
    return smoothedLocation;
}

4. 后台执行Firebase GeoFire操作

将位置回调中的Firebase IO操作放到后台线程,避免阻塞主线程。

// 在位置回调中修改GeoFire更新逻辑
new Thread(() -> {
    String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
    DatabaseReference ref = FirebaseDatabase.getInstance().getReference("BikersAvailable");
    GeoFire geoFire = new GeoFire(ref);
    geoFire.setLocation(userId, new GeoLocation(smoothLocate.getLatitude(),smoothLocate.getLongitude()));
}).start();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:14:58