You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ArcGIS SDK 100.2.1离线路线创建报错及旧版本示例适配咨询

解决ArcGIS SDK 100.2.1离线路线创建的"Cannot call this method in this context"错误

首先得说,100.x系列的ArcGIS Runtime SDK和10.2.x的API差异非常大,旧示例的写法完全不适用于新SDK,这是你遇到问题的核心原因。下面我会一步步帮你实现离线路线创建,并解决这个线程上下文的报错。

一、错误原因分析

这个报错几乎都是线程上下文不正确导致的:ArcGIS Runtime SDK 100.x中,所有耗时的地理操作(比如加载本地网络数据集、计算路由)必须在后台线程执行;而涉及UI更新或者组件初始化的部分,必须在主线程完成。如果搞混了线程,就会抛出这个异常。

二、离线路线创建的正确步骤(针对100.2.1)

假设你已经有包含网络数据集的离线地理数据库(.geodatabase),下面是完整的实现流程:

1. 准备离线资源

确保你的离线geodatabase包含:

  • 可用的网络数据集(用于路由计算)
  • 可选的定位点数据(起点、终点)

2. 初始化离线RouteTask

不要在主线程中直接初始化RouteTask或者加载网络数据集,必须用后台线程(比如AsyncTask,100.2.1时期Android还没普及Coroutine,用AsyncTask更稳妥)。

示例代码:

// 在Activity中启动后台加载任务
new RouteLoadTask().execute();

// 后台加载RouteTask的任务类
private class RouteLoadTask extends AsyncTask<Void, Void, RouteTask> {
    @Override
    protected RouteTask doInBackground(Void... voids) {
        try {
            // 本地geodatabase路径(示例为内部存储路径,可根据你的存储位置调整)
            String gdbPath = getFilesDir() + "/your_offline_data.gdb";
            Geodatabase geodatabase = new Geodatabase(gdbPath);
            
            // 替换成你自己的网络数据集名称
            String networkDatasetName = "CityStreets_ND";
            NetworkDataset networkDataset = geodatabase.getNetworkDataset(networkDatasetName);
            
            // 创建离线RouteTask实例
            return RouteTask.createFromNetworkDataset(networkDataset);
        } catch (ArcGISRuntimeException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    protected void onPostExecute(RouteTask routeTask) {
        super.onPostExecute(routeTask);
        if (routeTask != null) {
            // 主线程中处理初始化完成逻辑,比如获取默认路由参数
            getDefaultRouteParams(routeTask);
        } else {
            Toast.makeText(RoutingActivity.this, "离线路由资源加载失败", Toast.LENGTH_SHORT).show();
        }
    }
}

3. 获取路由参数并计算路线

获取默认参数、计算路由的操作都需要在后台线程执行,只有结果处理可以放在主线程:

private void getDefaultRouteParams(RouteTask routeTask) {
    new AsyncTask<RouteTask, Void, RouteParameters>() {
        @Override
        protected RouteParameters doInBackground(RouteTask... routeTasks) {
            try {
                // 获取默认路由参数,必须在后台线程
                return routeTasks[0].createDefaultParameters();
            } catch (ArcGISRuntimeException e) {
                e.printStackTrace();
                return null;
            }
        }

        @Override
        protected void onPostExecute(RouteParameters params) {
            super.onPostExecute(params);
            if (params != null) {
                // 设置起点和终点(替换成你的实际点位)
                MapPoint start = new MapPoint(-118.2437, 34.0522, SpatialReferences.getWgs84());
                MapPoint end = new MapPoint(-118.2500, 34.0580, SpatialReferences.getWgs84());
                
                // 添加停靠点到参数
                params.setStops(new Stop[]{new Stop(start), new Stop(end)});
                
                // 启动路由计算任务
                new RouteCalculateTask().execute(routeTask, params);
            }
        }
    }.execute(routeTask);
}

// 计算路由的后台任务
private class RouteCalculateTask extends AsyncTask<Object, Void, RouteResult> {
    @Override
    protected RouteResult doInBackground(Object... objects) {
        RouteTask task = (RouteTask) objects[0];
        RouteParameters params = (RouteParameters) objects[1];
        
        try {
            // 执行路由计算,必须在后台线程
            return task.solveRoute(params);
        } catch (ArcGISRuntimeException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    protected void onPostExecute(RouteResult result) {
        super.onPostExecute(result);
        if (result != null && result.getRoutes().size() > 0) {
            // 主线程中处理路由结果,比如在地图上绘制路线
            Route route = result.getRoutes().get(0);
            Polyline routeLine = route.getRouteGeometry();
            
            // 创建路线图形并添加到地图(假设你已创建GraphicsOverlay)
            Graphic routeGraphic = new Graphic(routeLine, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 3));
            graphicsOverlay.getGraphics().add(routeGraphic);
        } else {
            Toast.makeText(RoutingActivity.this, "路由计算失败", Toast.LENGTH_SHORT).show();
        }
    }
}

4. 关键注意事项

  • 线程严格隔离:所有涉及GeodatabaseRouteTask的初始化和耗时操作,必须放在doInBackground中;UI更新(比如添加图形、提示)必须放在onPostExecute(主线程)。
  • 资源释放:使用完Geodatabase后记得调用close()方法,避免内存泄漏。
  • 权限配置:如果geodatabase在外部存储,确保App申请了READ_EXTERNAL_STORAGE权限;用内部存储(如示例中的getFilesDir())则无需额外权限。

三、其他排查方向

如果按上述步骤仍报错,检查以下几点:

  • 确认离线geodatabase中的网络数据集有效,可通过ArcGIS Pro打开验证。
  • 100.2.1版本的SDK集成是否正确,gradle依赖是否完整。
  • 不要在Application上下文或非UI线程中初始化MapView相关组件,MapView必须在Activity/Fragment的UI线程中创建。

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

火山引擎 最新活动