【ArcGIS Runtime SDK for Android-07】Tasks and jobs

任务(tasks)被绑定到在线或离线数据或服务,并提供使用这些资源执行异步操作(asynchronous operations)的方法。通过使用任务,你可以:

  • Download, collect, and update geographic information using GeodatabaseSyncTask
  • Download and display tiled basemaps using ExportTileCacheTask
  • Locate addresses and find addresses from map locations using LocatorTask
  • Calculate point-to-point or multi-stop routes and get driving directions using RouteTask
  • Perform complex GIS analysis by executing geoprocessing models using GeoprocessingTask

任务或者直接从任务上的异步方法返回结果,或者使用工作(jobs)来提供状态更新和结果。

1、任务(Tasks)

有些操作直接从任务上的异步方法返回结果,例如LocatorTask.geocodeAsync和RouteTask.solveRouteAsync。对于更复杂或运行时间更长的操作,任务使用工作代替。

要使用直接返回结果的任务:

a、通过初始化任务以使用所需的数据或服务来创建任务。

  • 有些操作可以在线或离线进行。

b、定义任务输入。

  • 有些操作只需要简单的值输入(例如,一个简单的地理编码操作可能只需要一个地址字符串作为输入)。
  • 其他则需要定义参数(例如,将地理编码操作限制到特定的国家)。

c、调用异步操作方法,传入定义的输入。

d、根据需要使用操作的结果,例如在地图上显示地理编码结果。

下面的代码使用默认的Esri全球定位器创建LocatorTask,并将地址传递给geocode。当操作完成时,将检索结果位置在GraphicsOverlay中显示。

// Call geocodeAsync passing in an address
final LocatorTask onlineLocator = new LocatorTask("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
final ListenableFuture<List<GeocodeResult>> geocodeFuture = onlineLocator.geocodeAsync("380 New York Street, Redlands, CA");
geocodeFuture.addDoneListener(new Runnable() {
  @Override
  public void run() {
    try {
      // Get the results of the async operation
      List<GeocodeResult> geocodeResults = geocodeFuture.get();

      if (geocodeResults.size() > 0) {
        // Use the first result - for example display in an existing Graphics Overlay
        GeocodeResult topResult = geocodeResults.get(0);
        Graphic gecodedLocation = new Graphic(topResult.getDisplayLocation(), topResult.getAttributes(),
            new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.SQUARE, Color.rgb(255, 0, 0), 20.0f));
        mGraphicsOverlay.getGraphics().add(gecodedLocation);
      }
    }
    catch (InterruptedException | ExecutionException e) {
      dealWithException(e); // deal with exception appropriately...
    }
  }
});

有些任务是可加载的,当您调用需要任务处于加载状态的异步方法(如上面所示)时,这些任务将加载它们自己。可加载对象通常需要在填充其属性之前加载。

(1)定义输入参数(Define input parameters)

任务提供了许多选项,允许您根据需要调整操作。例如,在地理编码时,可以将搜索限制在特定的区域、国家、地点类别和/或结果数量。当作者发布服务或打包资源时,他们可以为这些选项选择适合特定数据或服务最常用用例的默认值。

为了找到这些默认参数值,任务提供异步方法来创建参数对象,并使用这些特定于服务的值进行初始化。然后可以在使用参数值执行操作之前对其进行任何更改。以这种方式创建参数对象对于具有许多选项的操作特别有用,例如解决路径规划。

下面的代码获取RouteTask的默认参数,然后确保使用这些参数的结果将返回规划路径(route)和方向(direction),以及输出的空间参考与MapView的匹配。

// use async method on RouteTask to get default parameters (task can be loaded or not loaded)
final ListenableFuture<RouteParameters> defaultParametersFuture = routeTask.createDefaultParametersAsync();
defaultParametersFuture.addDoneListener(new Runnable() {
  @Override
  public void run() {
    try {
      // get the parameters from the future
      RouteParameters routeParameters = defaultParametersFuture.get();

      // update properties of route parameters
      routeParameters.setReturnDirections(true);
      routeParameters.setReturnRoutes(true);
      if (routeParameters.getOutputSpatialReference() != mapView.getSpatialReference()) {
        routeParameters.setOutputSpatialReference(mapView.getSpatialReference());
      }
      // Use the updated parameters to solve a route...
    }
    catch (InterruptedException | ExecutionException e) {
      dealWithException(e); // deal with exception appropriately...
    }
  }
});

或者,如果您知道要使用的所有输入参数的值,那么一些parameters对象具有构造函数,您可以使用这些构造函数。在参数设置简单的情况下,这可以更有效。

例如,下面的代码创建地理编码参数,这些参数将国家限制为地理编码,并限制返回的最大结果。

GeocodeParameters geocodeParams = new GeocodeParameters();
geocodeParams.setCountryCode("France");
geocodeParams.setMaxResults(5);

(2)在线或离线工作(Work online or offline)

许多任务可以通过使用服务进行在线工作,也可以通过使用本地数据和资源进行离线工作。例如,您可以使用默认Esri地理编码服务、您自己的地理编码服务、定位器文件(.loc)或移动地图包(.mmpk)对地址进行地理编码。

// create an online locator from a geocoding service - here we use esri's default global locator...
final LocatorTask onlineLocator = new LocatorTask("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");

// create an offline locator from a local .loc file - coverage will depend on the packaged locator dataset...
final LocatorTask offlineLocator = new LocatorTask(localLocatorPath + ".loc");

// mobile map packages can also contain locators - use this to get a reference to an offline locator...
final MobileMapPackage mmpk = new MobileMapPackage(localMmpkPath + ".mmpk");
    mmpk.addDoneLoadingListener(new Runnable() {
      @Override
      public void run() {
        if (mmpk.getLoadStatus() == LoadStatus.LOADED) {
          LocatorTask mmpkLocator = mmpk.getLocatorTask();
          // use locator from a mobile map package according to the packaged locator coverage...
        }
      }
    });
mmpk.loadAsync();

2、任务和工作(Tasks and jobs)

一些任务公开操作具有多个阶段(如准备和下载地理数据库)的操作,并可以生成多个进度消息(如完成百分比)。这些类型的任务总是绑定到ArcGIS Server或本地服务器。例如:在GeodatabaseSyncTask上生成geodatabaseasync。

这些任务不是直接返回结果,而是使用工作(jobs)来监视状态、返回进度更新和结果。每个工作表示任务的特定操作。工作对于长时间运行的操作很有用,因为它们也可以暂停、恢复和取消。您的应用程序可以支持用户操作或主机操作系统终止正在运行的工作对象,然后重新创建和恢复工作。

使用这样的操作:

a、通过初始化任务以使用所需的数据或服务来创建任务。

b、定义任务的输入参数。

c、调用异步操作方法获取工作,并传入定义的输入参数。

d、开始这项工作。

e、还可以选择侦听工作状态的更改并检查工作消息,例如更新UI并向用户报告进度。

f、监听工作完成情况,并从操作中获取结果。检查工作中的错误,如果成功,使用结果。

// Create the export tile cache
ExportTileCacheTask exportTilesTask = new ExportTileCacheTask("http://sampleserver6.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer");

// Define the parameters for the new tile cache - in this case, using the parameter object constructor
ExportTileCacheParameters exportTilesParameters = new ExportTileCacheParameters();
exportTilesParameters.getLevelIDs().addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
exportTilesParameters.setAreaOfInterest(
    new Envelope(-1652366.0, 2939253.0, 2537014.0, 8897484.0, SpatialReferences.getWebMercator()));

// Create the export task, passing in parameters, and file path ending in ".tpk"
final ExportTileCacheJob exportJob = exportTilesTask.exportTileCacheAsync(exportTilesParameters, exportedTpkPath);

// Listen for job status updates, and report the most recent message to the user...
exportJob.addJobChangedListener(new Runnable() {
  @Override
  public void run() {
    List<Job.Message> messages = exportJob.getMessages();
    updateUiWithProgress(messages.get(messages.size() - 1).getMessage());
  }
});

// Listen for when the job is completed
exportJob.addJobDoneListener(new Runnable() {
  @Override
  public void run() {
    // Check if there was an error
    if (exportJob.getError() != null) {
      dealWithException(exportJob.getError()); // deal with exception appropriately...
      return;
    }

    if (exportJob.getStatus() == Job.Status.SUCCEEDED) {
      // Get the TileCache resulting from the successfull export job, and use it by adding a layer to a MapView
      final TileCache exportedTileCache = exportJob.getResult();
      ArcGISTiledLayer tiledLayer = new ArcGISTiledLayer(exportedTileCache);
      mapView.getMap().getOperationalLayers().add(tiledLayer);
    }
  }
});

// Start the ExportTileCacheJob
exportJob.start();

调用Job.getStatus检索当前工作流中的节点。启动工作定期接收作业更改事件;随着工作的进展,这种情况发生的频率越来越低;对于每个调用,工作中可能添加了多个JobMessage。对于成功和失败,一旦工作完成,就会调用已完成的侦听器。已完成的工作,无论成功与否,都不能重新启动。

(1)Report job progress

工作表示可能需要一些时间才能完成的异步运行操作。如前所述,您可以监视工作状态的更改,以便在作业完成、失败或被取消时发出通知,但是在这之间的时间呢?用户可能会在等待一项长时间的工作完成而没有得到关于其进展的反馈时感到沮丧。幸运的是,工作提供了一种机制,用于报告它们所表示的正在运行的操作的当前进度(完成百分比)。

当工作运行时,将调用工作更改的侦听器(使用Job.addJobChangedListener方法进行监听)。您可以从工作的progress属性获取作业在任意点的当前进度,该属性是一个整数,表示已完成的操作的百分比。这允许您的应用程序使用诸如进度条之类的UI元素来提供关于正在运行的工作状态的更具体的信息。

下面的示例使用工作的完成百分比更新UI元素,然后在完成时获取切片缓存。

// Start the ExportTileCacheJob
exportJob.start();
// Add a listener to display the % of the job done
exportJob.addProgressChangedListener(new Runnable() {
  @Override public void run() {
    updateUiWithProgress("Progress: " + String.valueOf(exportJob.getProgress()) +"%");
  }
});
// Add a listener to get the result when job is done
exportJob.addJobDoneListener(new Runnable() {
  @Override public void run() {
    TileCache exportedTileCacheResult = exportJob.getResult();
  }
});

3、Pause, resume, or cancel job

工作的设计目的是在工作运行时有效地处理用户退出应用程序,并处理被主机操作系统终止的应用程序。工作还处理操作的暂停和取消。

(1)Cancel a job

有时候,工作的结果不再是必须的。例如,用户可能会改变他们想要下载的切片缓存的区域,并想要取消工作并重新开始。

调用Job.cancel将立即将其状态更改为Job.Status.FAILED,并向工作错误对象添加其他信息。将调用作业完成侦听器。error对象指示错误域和代码,这允许您识别取消何时发生。

下面的代码显示,对于一个正在运行的ExportTileCacheJob,添加了一个JobDoneListener。在侦听器中,代码检查适当的错误代码和表示工作已被取消的域。此时,代码检查是否已经创建了切片缓存文件,如果已经创建,则删除它。

// For a job that is running, listen for when the job is completed
runningJob.addJobDoneListener(new Runnable() {
  @Override
  public void run() {
    // Check if there was an error
    ArcGISRuntimeException jobError = runningJob.getError();
    if (jobError != null) {

      // Failure status can indicate cancellation, or other types of failure
      if (runningJob.getStatus() == Job.Status.FAILED) {

        // Check the error information to confirm if this was a user cancellation
        if ((jobError.getErrorCode() == 18) &&
            (jobError.getErrorDomain() == ArcGISRuntimeException.ErrorDomain.ARCGIS_RUNTIME)) {

          // UI can be updated to indicate cancellation
          updateUiWithProgress("Export has been cancelled");

          // Could check if tile cache was downloaded before the task was cancelled, and clean up the file...
          File tileCacheFile = new File(exportedTpkPath);
          if (tileCacheFile.exists()) {
            tileCacheFile.delete();
          }
          return;
        }
      }

      dealWithException(jobError); // Deal with other types of failure...
      return;
    }

    dealWithJobDoneSuccess(); // Deal with a successful job
  }
});

无法重新启动已取消的工作,尽管可以通过重用相同的参数来启动新作业。取消工作并不一定会停止任何服务器端进程,因为并非所有服务都支持服务器端取消。

(2)Pause and resume a job

工作可能是长时间运行的操作,因此不能保证在应用程序运行时工作就能完成。可以使用job.pause暂停工作。例如,一个应用是后台的,没有后台操作的权限。如果用户希望出于任何原因暂时停止网络访问,暂停也可能是有用的。

暂停工作不会接收工作更改的消息。暂停工作不会阻止任何服务器端进程的执行。当工作暂停时,未完成的请求可以完成,因此恢复工作可能会使其处于与暂停时不同的状态。

如果应用程序是后台的,或者进程以其他方式终止,则可以将工作序列化为JSON来持久化工作。当您再次反序列化它时,工作将处于 Job.Status.PAUSED状态中,而不是序列化时的状态,应该重新启动以恢复监听以完成。工作更改侦听器是更新工作JSON以便应用程序存储的好地方。

下面的代码显示,对于一个正在运行的工作,将该工作序列化为JSON

mRunningJob.addJobChangedListener(new Runnable() {
  @Override
  public void run() {
    // Every time the job changes, update the stored JSON that represents the Job.
    mJobJson = mRunningJob.toJson();
  }
});

This JSON can then be saved when appropriate, for example by overriding the onSaveInstanceState in an Activity and saving the JSON String to the Bundle parameter. The JSON can be similarly retrieved when appropriate, for example in the onRestoreInstanceState or onCreate method of the Activity, depending on if the job should be considered persistent or temporary data.

The Job can then be deserialized back from stored JSON, and restarted. Remember to set the job changed and done listeners again to be informed when the job changes, and when it is complete and the result can be retrieved.

private void deserializeFromJson() {
  if ( (mJobJson != null) && (!mJobJson.isEmpty())) {
    mRunningJob = Job.fromJson(mJobJson);

    if (mRunningJob != null) {
      // Deserialized jobs have Job.Status.PAUSED, so restart the job.
      mRunningJob.start();

      // Resume listening for status changes and job completion.
      mRunningJob.addJobChangedListener(new Runnable() {
        @Override
        public void run() {
          dealWithJobChanged(); // See examples above
        }
      });

      mRunningJob.addJobDoneListener(new Runnable() {
        @Override
        public void run() {
          dealWithJobDone(); // See examples above
        }
      });
    }
  }
}

(3)Loss of network connection

此外,使用服务的工作用于处理网络连接暂时丢失而不需要立即暂停的情况。启动的工作将在长达10分钟的时间内忽略网络错误等错误。如果错误持续更长时间,工作将失败,消息将指示网络连接的丢失。

为了处理部分连接的工作流,当应用程序检测到网络连接丢失了几分钟时,您可以序列化并暂停工作,以避免纯粹由于缺少网络连接而导致工作失败(因为失败的工作无法重新启动)。然后可以反序列化工作,并在恢复连接时恢复工作。

从Android 6.0开始,Doze和App Standby的省电功能也会影响应用程序的网络连接。同样,如果应用程序进入这些状态,您可能希望暂停正在运行的作业,以避免由于缺乏持久网络连接而导致工作失败。你的应用程序可以检查Android PowerManager.isDeviceIdleMode和PowerManager.isPowerSaveMode方法,或在进入或退出这些模式时使用广播意图进行响应。

参考链接:

https://developers.arcgis.com/android/latest/guide/tasks-and-jobs.htm

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值