[TOC]
介紹
任務(wù)綁定到聯(lián)機(jī)或脫機(jī)數(shù)據(jù)或服務(wù)烦周,并提供使用這些資源執(zhí)行異步操作的方法帚稠。通過(guò)使用任務(wù)孵运,您可以:
- 使用 GeodatabaseSyncTask 下載,收集和更新地理信息
- 使用 ExportTileCacheTask 下載并顯示平鋪的底圖
- 使用 LocatorTask查找地址并從地圖位置查找地址
- 使用 RouteTask 計(jì)算點(diǎn)對(duì)點(diǎn)或多站路線并獲取行車(chē)路線
- 通過(guò)使用 GeoprocessingTask 執(zhí)行地理處理模型來(lái)執(zhí)行復(fù)雜的GIS分析
任務(wù)要么直接從任務(wù)上的異步方法返回結(jié)果惠呼,要么使用作業(yè)(下文有介紹)來(lái)提供狀態(tài)更新和結(jié)果
Tasks
某些操作直接從任務(wù)上的異步方法返回其結(jié)果导俘,例如LocatorTask.geocodeAsync
和RouteTask.solveRouteAsync
。對(duì)于更復(fù)雜或更長(zhǎng)時(shí)間運(yùn)行的操作剔蹋,使用 jobs 代替 tasks旅薄。
要使用直接返回結(jié)果的任務(wù):
- 通過(guò)初始化任務(wù)來(lái)創(chuàng)建任務(wù)以使用所需的數(shù)據(jù)或服務(wù)。 某些操作可以在線和離線工作泣崩。
- 定義任務(wù)的輸入內(nèi)容少梁。
2.1.某些操作僅需要輸入簡(jiǎn)單的值(例如,簡(jiǎn)單的地理編碼操作可能只需要地址字符串作為輸入)
2.2.其他需要定義參數(shù)(例如矫付,將地理編碼操作限制到特定國(guó)家/地區(qū))凯沪。 - 調(diào)用異步操作方法,傳入您定義的輸入內(nèi)容买优。
- 根據(jù)需要使用請(qǐng)求的結(jié)果妨马,例如在地圖上顯示地理編碼結(jié)果。
下面的代碼使用默認(rèn)的Esri全局定位器創(chuàng)建LocatorTask
而叼,并將地址傳遞給地理編碼身笤。操作完成后,將檢索結(jié)果位置并顯示在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) {
//顯示結(jié)果
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...
}
}
});
某些任務(wù)是可加載的液荸,并且在調(diào)用需要任務(wù)處于加載狀態(tài)的異步方法(如上所示)時(shí)將自行加載。
Define input parameters(定義輸入?yún)?shù))
Tasts 提供了許多選項(xiàng)脱篙,使您可以根據(jù)需要定制操作娇钱。例如,在進(jìn)行地理編碼時(shí)绊困,您可以將搜索范圍限制在特定區(qū)域文搂,國(guó)家/地區(qū),地點(diǎn)類(lèi)別和/或結(jié)果數(shù)量秤朗。當(dāng)作者發(fā)布服務(wù)或打包資源時(shí)煤蹭,他們可以為發(fā)布的服務(wù)從選擇適合特定數(shù)據(jù)的選項(xiàng)或者最常見(jiàn)用例的選項(xiàng)選擇默認(rèn)值。
要查找這些默認(rèn)參數(shù)值取视,任務(wù)會(huì)提供創(chuàng)建參數(shù)對(duì)象的異步方法硝皂,并使用這些特定于服務(wù)的值進(jìn)行初始化。然后作谭,您可以在執(zhí)行操作之前對(duì)參數(shù)值進(jìn)行任意更改稽物。以這種方式創(chuàng)建參數(shù)對(duì)象對(duì)于具有許多選項(xiàng)的操作尤其有用,例如計(jì)算路徑折欠。
下面的代碼獲取 RouteTask
的默認(rèn)參數(shù)贝或,然后確保使用這些參數(shù)的結(jié)果將返回路徑和方向吼过,并且輸出空間參考也匹配MapView
的結(jié)果。
// 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...
}
}
});
如果您知道所有輸入?yún)?shù)的值咪奖,則可以使用你想使用的具有構(gòu)造函數(shù)參數(shù)對(duì)象盗忱。在參數(shù)設(shè)置簡(jiǎn)單的情況下,這可以更有效羊赵。
例如售淡,下面的代碼會(huì)創(chuàng)建地理編碼參數(shù),以限制要進(jìn)行地理編碼的國(guó)家/地區(qū)慷垮,并限制返回的最大結(jié)果揖闸。
GeocodeParameters geocodeParams = new GeocodeParameters();
geocodeParams.setCountryCode("France");
geocodeParams.setMaxResults(5);
Work online or offline
許多任務(wù)可以通過(guò)使用服務(wù)在線工作,也可以使用本地?cái)?shù)據(jù)和資源離線工作料身。
例如汤纸,您可以使用默認(rèn)的Esri地理編碼服務(wù),您自己的地理編碼服務(wù)芹血,定位器文件(.loc)或移動(dòng)地圖包(.mmpk)對(duì)地址進(jìn)行地理編碼贮泞。
//使用在線服務(wù)
final LocatorTask onlineLocator = new LocatorTask("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
//使用離線定位器文件
final LocatorTask offlineLocator = new LocatorTask(localLocatorPath + ".loc");
// 使用移動(dòng)地圖包
final MobileMapPackage mmpk = new MobileMapPackage(localMmpkPath + ".mmpk");
mmpk.addDoneLoadingListener(new Runnable() {
@Override
public void run() {
if (mmpk.getLoadStatus() == LoadStatus.LOADED) {
LocatorTask mmpkLocator = mmpk.getLocatorTask();
}
}
});
mmpk.loadAsync();
Tasks and jobs
某些任務(wù)會(huì)公開(kāi)具有多個(gè)階段的操作(例如準(zhǔn)備和下載地理數(shù)據(jù)庫(kù)),并可以生成多個(gè)進(jìn)度消息(例如完成百分比)。這些類(lèi)型的任務(wù)始終綁定到ArcGIS 服務(wù)或本地服務(wù)器幔烛。一個(gè)例子是GeodatabaseSyncTask
上的generateGeodatabaseAsync
啃擦。
這些任務(wù)不是直接返回結(jié)果,而是使用作業(yè)來(lái)監(jiān)視狀態(tài)饿悬,返回進(jìn)度更新并返回結(jié)果令蛉。每個(gè)Job代表一個(gè)任務(wù)的特定操作。作業(yè)對(duì)于長(zhǎng)時(shí)間運(yùn)行的操作很有用狡恬,因?yàn)樗鼈円部梢詴和V槭澹謴?fù)和取消。您的應(yīng)用程序可以支持用戶或主機(jī)操作系統(tǒng)終止正在運(yùn)行的作業(yè)對(duì)象弟劲,然后在以后重新創(chuàng)建并恢復(fù)該作業(yè)祷安。
要使用以下操作
- 通過(guò)初始化任務(wù)來(lái)創(chuàng)建任務(wù)以使用所需的數(shù)據(jù)或服務(wù)
- 定義任務(wù)的輸入?yún)?shù)。
- 調(diào)用異步操作方法來(lái)獲取作業(yè)兔乞,傳入您定義的輸入?yún)?shù)汇鞭。
- 開(kāi)始工作
- (可選)偵聽(tīng)作業(yè)狀態(tài)的更改并檢查作業(yè)消息,例如更新UI并向用戶報(bào)告進(jìn)度庸追。
- 聽(tīng)取工作完成情況并從操作中獲取結(jié)果霍骄。檢查作業(yè)中的錯(cuò)誤,如果成功锚国,請(qǐng)使用結(jié)果腕巡。
例:
// 創(chuàng)建在線平鋪服務(wù)任務(wù)
ExportTileCacheTask exportTilesTask = new ExportTileCacheTask("http://sampleserver6.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer");
// 參數(shù)對(duì)象
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()));
// 創(chuàng)建Job
final ExportTileCacheJob exportJob = exportTilesTask.exportTileCacheAsync(exportTilesParameters, exportedTpkPath);
// 監(jiān)聽(tīng) Job 進(jìn)度玄坦,修改進(jìn)度條
exportJob.addJobChangedListener(new Runnable() {
@Override
public void run() {
List<Job.Message> messages = exportJob.getMessages();
updateUiWithProgress(messages.get(messages.size() - 1).getMessage());
}
});
// 監(jiān)聽(tīng) Job 結(jié)果 血筑,完成后使用結(jié)果
exportJob.addJobDoneListener(new Runnable() {
@Override
public void run() {
// 發(fā)生錯(cuò)誤
if (exportJob.getError() != null) {
dealWithException(exportJob.getError());
return;
}
// 執(zhí)行成功
if (exportJob.getStatus() == Job.Status.SUCCEEDED) {
// 在地圖中顯示結(jié)果
final TileCache exportedTileCache = exportJob.getResult();
ArcGISTiledLayer tiledLayer = new ArcGISTiledLayer(exportedTileCache);
mapView.getMap().getOperationalLayers().add(tiledLayer);
}
}
});
// 執(zhí)行 Job
exportJob.start();
調(diào)用Job.getStatus
將檢索作業(yè)工作流中的當(dāng)前點(diǎn).開(kāi)始工作定期接收工作變更事件;隨著工作的進(jìn)展绘沉,這種情況會(huì)隨著頻率的降低而發(fā)生;每個(gè)呼叫可能已為作業(yè)添加了多個(gè)JobMessage。對(duì)于成功和失敗豺总,一旦作業(yè)完成车伞,就會(huì)調(diào)用作業(yè)監(jiān)聽(tīng)器。已完成的作業(yè)喻喳,無(wú)論是成功還是失敗另玖,都無(wú)法重新啟動(dòng)。
Report job progress
job表示可能需要一些時(shí)間才能完成的異步運(yùn)行操作表伦。如前所述谦去,您可以在作業(yè)完成,失敗或被取消時(shí)監(jiān)視作業(yè)狀態(tài)的更改蹦哼,但是中間的時(shí)間如何呢鳄哭?用戶可能會(huì)因等待長(zhǎng)時(shí)間工作而無(wú)法獲得有關(guān)其進(jìn)度的反饋而感到不耐煩,jobs 提供了一種機(jī)制纲熏,用于報(bào)告它們所代表的運(yùn)行操作的當(dāng)前進(jìn)度(完成百分比)妆丘。
當(dāng)作業(yè)運(yùn)行時(shí),調(diào)用作業(yè)更改的偵聽(tīng)器(使用Job.addJobChangedListener
方法偵聽(tīng))局劲。您可以從作業(yè)的Progress屬性中獲取作業(yè)的當(dāng)前進(jìn)度勺拣,該屬性是一個(gè)整數(shù),表示已完成操作的百分比鱼填。這允許您的應(yīng)用程序使用UI元素(例如進(jìn)度條)提供有關(guān)正在運(yùn)行的作業(yè)狀態(tài)的更多特定信息药有。
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();
}
});
Pause, resume, or cancel job
作業(yè)旨在有效地處理在作業(yè)運(yùn)行時(shí)退出應(yīng)用程序的用戶,并處理由主機(jī)操作系統(tǒng)終止的應(yīng)用程序苹丸。Jobs 還處理明確的暫停和取消操作塑猖。
Cancel a job
有時(shí)候不再需要工作的結(jié)果。例如谈跛,用戶可以改變他們想要下載的圖塊緩存區(qū)域的想法羊苟,并且想要取消作業(yè)并重新開(kāi)始。
在作業(yè)上調(diào)用Job.cancel會(huì)立即將其狀態(tài)更改為Job.Status.FAILED感憾,并將其他信息添加到作業(yè)錯(cuò)誤對(duì)象蜡励。將調(diào)用作業(yè)完成偵聽(tīng)器。錯(cuò)誤對(duì)象指示錯(cuò)誤域和代碼阻桅,允許您識(shí)別何時(shí)發(fā)生取消凉倚。
下面的代碼顯示,對(duì)于正在運(yùn)行的ExportTileCacheJob
嫂沉,添加了JobDoneListener
稽寒。在偵聽(tīng)器中,代碼檢查相應(yīng)的錯(cuò)誤代碼和域趟章,指示作業(yè)已被取消杏糙。此時(shí)慎王,代碼檢查以防已創(chuàng)建切片緩存文件,如果已創(chuàng)建宏侍,則刪除它赖淤。
// 添加監(jiān)聽(tīng)
runningJob.addJobDoneListener(new Runnable() {
@Override
public void run() {
// 經(jīng)檢測(cè)是否 error
ArcGISRuntimeException jobError = runningJob.getError();
if (jobError != null) {
//檢測(cè)是否是 failed
if (runningJob.getStatus() == Job.Status.FAILED) {
// 是否是用戶取消
if ((jobError.getErrorCode() == 18) &&
(jobError.getErrorDomain() == ArcGISRuntimeException.ErrorDomain.ARCGIS_RUNTIME)) {
// 取消后的UI刷行
updateUiWithProgress("Export has been cancelled");
// 檢測(cè)是否已經(jīng)緩存
File tileCacheFile = new File(exportedTpkPath);
if (tileCacheFile.exists()) {
tileCacheFile.delete();
}
return;
}
}
dealWithException(jobError); // 處理其他原因造船的錯(cuò)誤
return;
}
dealWithJobDoneSuccess(); // 成功后的處理
}
});
雖然您可以通過(guò)重復(fù)使用相同的參數(shù)來(lái)啟動(dòng)新作業(yè),但無(wú)法重新啟動(dòng)已取消的作業(yè)谅河。取消作業(yè)不一定會(huì)停止任何服務(wù)器端進(jìn)程咱旱,因?yàn)椴⒎撬蟹?wù)都支持服務(wù)器端的取消。
Pause and resume a job
job 可以是長(zhǎng)時(shí)間運(yùn)行的操作绷耍,因此無(wú)法保證在應(yīng)用程序運(yùn)行時(shí)它們將完成吐限。您可以使用Job.pause
顯式暫停作業(yè)。例如褂始,當(dāng)應(yīng)用程序切換到后臺(tái)并且沒(méi)有后臺(tái)操作權(quán)限時(shí)毯盈。如果用戶希望出于任何原因暫時(shí)停止網(wǎng)絡(luò)訪問(wèn),則暫停也可能是有用的病袄。
暫停 job 將不會(huì)收到作業(yè)更改的消息搂赋。暫停作業(yè)不會(huì)阻止任何服務(wù)器端進(jìn)程執(zhí)行。當(dāng)作業(yè)暫停時(shí)益缠,未完成的請(qǐng)求可以完成脑奠,因此恢復(fù)作業(yè)可能會(huì)導(dǎo)致它與暫停時(shí)的狀態(tài)不同。
您可以將 job 序列化為JSON幅慌,以便在您的應(yīng)用程序處于后臺(tái)運(yùn)行時(shí)保持該作業(yè)宋欺,否則該過(guò)程將被終止。再次反序列化時(shí)胰伍,job 將處于Job.Status.PAUSED
狀態(tài)齿诞,無(wú)論其序列化時(shí)的狀態(tài)如何,應(yīng)重新啟動(dòng)以繼續(xù)偵聽(tīng)完成骂租。Job 更改的偵聽(tīng)器可以是您的應(yīng)用程序更新作業(yè)JSON以存儲(chǔ)的好地方祷杈。
下面的代碼顯示,對(duì)于現(xiàn)有正在運(yùn)行的Job渗饮,將作業(yè)序列化為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();
}
});
然后可以在適當(dāng)時(shí)保存此JSON,例如互站,通過(guò)覆蓋Activity中的onSaveInstanceState
并將JSON String保存到Bundle
參數(shù)私蕾。可以在適當(dāng)?shù)臅r(shí)候類(lèi)似地檢索JSON胡桃,例如在Activity的onRestoreInstanceState或onCreate方法中踩叭,具體取決于作業(yè)是應(yīng)該被視為持久數(shù)據(jù)還是臨時(shí)數(shù)據(jù)。
反序列化保存的 JSON數(shù)據(jù)
private void deserializeFromJson() {
if ( (mJobJson != null) && (!mJobJson.isEmpty())) {
mRunningJob = Job.fromJson(mJobJson);
if (mRunningJob != null) {
// 反序列化Job.Status.PAUSED狀態(tài)的 job,
mRunningJob.start();
mRunningJob.addJobChangedListener(new Runnable() {
@Override
public void run() {
dealWithJobChanged();
}
});
mRunningJob.addJobDoneListener(new Runnable() {
@Override
public void run() {
dealWithJobDone();
}
});
}
}
}