2016-08-16 100 views
0

我有我的代碼有問題,我有我的活動,我用它來調用谷歌API和檢索JSON,反序列化他們,並使用它的多義線繪製在地圖上。如何在所有AsyncTasks完成後執行onMapReady()回調?

問題是,在執行我的異步任務後,會立即執行發送onMapReady()的回調函數的getMapAsync(),該函數將檢索必要的數據以創建映射。

我如何在不停止UI線程的情況下做到這一點?我試着調用.execute.get()來凍結UI線程。但是如果我這樣做,我將無法使用ProgressDialog通知用戶從服務器獲取數據的延遲,這些數據將暴露給凍結的用戶界面,直到任務完成。我怎樣才能做到這一點?

public class RouteAssistantActivity extends Activity implements OnMapReadyCallback{ 

public GoogleMapsDirectionsResponse dirRes; 
public GoogleMapsDistanceResponse disRes; 

public String jsonString; 
private String mapsAPIKey; 
private String directionsBaseURL; 
private String distanceBaseURL; 

MapFragment mapFragment; 
private ProgressDialog progress; 

public void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_ra_route_assisstant); 

    mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.ra_map); 
    progress = new ProgressDialog(RouteAssistantActivity.this); 
    progress.setTitle("Please Wait"); 
    progress.setMessage("Retrieving Data from the Server"); 
    progress.setIndeterminate(true); 

    try { 
     ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); 

     if (appInfo.metaData != null) { 
      mapsAPIKey = appInfo.metaData.getString("com.google.android.maps.v2.API_KEY"); 
      directionsBaseURL = appInfo.metaData.getString("com.google.android.maps.directions.baseURL"); 
      distanceBaseURL = appInfo.metaData.getString("com.google.android.maps.distance.baseURL"); 
     } 

    } catch (PackageManager.NameNotFoundException e) { 
     Log.e("Meta Error", "Meta Data not found. Please check the Manifest and the Meta Data Package Names"); 
     e.printStackTrace(); 
    } 

    //Test 
    String directionsURL = directionsBaseURL+"origin=6.948109,79.858191&destination=6.910176,79.894347&key="+mapsAPIKey; 
    String distanceURL = distanceBaseURL+"units=metric&origins=6.948109,79.858191&destinations=6.910176,79.894347&key="+mapsAPIKey; 

    Log.e("CA Debug","URL : " + directionsURL); 
    Log.e("CA Debug","URL : " + distanceURL); 

    new configurationSyncTask().execute(distanceURL,"distance"); 
    new configurationSyncTask().execute(directionsURL, "direction"); 

    mapFragment.getMapAsync(this); 

} 

@Override 
public void onMapReady(GoogleMap googleMap) { 
    LatLng rajagiriya = new LatLng(6.910176, 79.894347); 

    String points = dirRes.getRoutes().get(0).getOverviewPolyline(); 
    List<LatLng> list = PolyUtil.decode(points); 

    googleMap.setMyLocationEnabled(true); 
    googleMap.getUiSettings().setRotateGesturesEnabled(true); 
    googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rajagiriya, 13)); 

    googleMap.addMarker(new MarkerOptions() 
      .title("Rajagiriya") 
      .snippet("My Place") 
      .position(rajagiriya)); 

    googleMap.addPolyline(new PolylineOptions() 
      .geodesic(false) 
      .addAll(list) 
      .color(Color.RED) 
      .width(25)); 
} 

private class configurationSyncTask extends AsyncTask<String, Void, String> { 

    @Override 
    protected void onPreExecute() { 
     progress.show(); 
    } 

    @Override 
    protected String doInBackground(String... params) { 

     String url = params[0]; 
     String type = params[1]; 

     Log.d("CA Debug", getClass().getSimpleName() + " --> Real URL : " + url); 
     Log.d("CA Debug", getClass().getSimpleName() + " --> doInBackground requesting content"); 

     jsonString = requestContent(url); 

     // if the output is null, stop the current task 
     if (jsonString == null) { 
      Log.d("CA Debug", getClass().getSimpleName() + " --> Stopping Async Task"); 
      this.cancel(true); 
      Log.d("CA Debug", getClass().getSimpleName() + " --> Async Task Stopped"); 
     } 

     return type; 
    } 

    @Override 
    protected void onPostExecute(String types) { 

     if (types.equalsIgnoreCase("distance")) { 
      disRes = GMapsDistanceResponseJSONDeserializer.deserialize(jsonString); 
     } if (types.equalsIgnoreCase("directions")) { 
      dirRes = GMapsDirectionsResponseJSONDeserializer.deserialize(jsonString); 
     } 

     progress.dismiss(); 
    } 


} 

public String requestContent(String url) { 

    Log.d("CA Debug",getClass().getSimpleName()+" --> URL : "+url); 

    try { 
     URL urlObj = new URL(url); 
     HttpsURLConnection con = (HttpsURLConnection) urlObj.openConnection(); 
     con.setChunkedStreamingMode(0); 
     con.setRequestMethod("GET"); 

     SSLContext sc = SSLContext.getInstance("TLS"); 
     sc.init(null,null, new SecureRandom()); 
     con.setSSLSocketFactory(sc.getSocketFactory()); 

     InputStream clientResponse; 
     String jsonString; 
     int status = con.getResponseCode(); 

     if(status >= HttpURLConnection.HTTP_BAD_REQUEST){ 
      Log.d("CA Debug", getClass().getSimpleName()+" --> Bad Request"); 
      jsonString = null; 
     } else { 
      Log.d("CA Debug", getClass().getSimpleName()+" --> converting Stream To String"); 
      clientResponse = con.getInputStream(); 
      jsonString = convertStreamToString(clientResponse); 
     } 

     Log.d("CA Debug", getClass().getSimpleName()+" --> JSON STRING : " + jsonString); 

     return jsonString; 
    } catch (IOException | NoSuchAlgorithmException | KeyManagementException e) { 

     Log.d("CA Debug", getClass().getSimpleName()+" --> Error when creating an Input Stream"); 
     e.printStackTrace(); 

    } 
    return null; 
} 

public String convertStreamToString(InputStream is) { 
    BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
    StringBuilder sb = new StringBuilder(); 
    String line = null; 

    try { 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
    } catch (IOException e) { 
    } finally { 
     try { 
      is.close(); 
     } catch (IOException e) { 
     } 
    } 

    return sb.toString(); 
} 

} 
+0

你有configurationSyncTask()的問題。爲什麼你叫configurationSyncTask()twise? – darwin

+0

@達爾文我傳遞了兩個不同的參數。參數是導致不同API的URL。有沒有更好的方法來做到這一點?歡迎提出建議。 – k9yosh

+0

onMapReady()完成後執行任務嗎? – Blackkara

回答

2

快速和有些髒解決方案將是在一個單一的AsyncTask執行既AsyncTasks,然後在其onPostExecute代碼調用getMapAsync。這樣,在處理地圖準備工作之前,您將確保完成任務。

+0

我會試一試,讓你知道。謝謝。 – k9yosh

+0

是否有可能以嵌套方式執行異步任務?它說execute()應該在主線程中調用。 – k9yosh

+0

這不起作用。我只能從主線程調用工作線程。所以,即使我在前一個工作線程中創建新的工作線程,我將不得不調用onPostExecute()內部的execute()方法,這會返回主UI線程。因此,最終在執行這兩個新的工作線程之後,它會立即執行getMapAsync(),而不會等待那些導致NullPointerException的兩個新線程,就像我原來的情況一樣。無論如何感謝您的幫助。 – k9yosh

0
  • 首先,在onMapReady之後運行任務,因爲您將擺脫 關注已準備好的地圖。
  • 你的異步任務不平行,他們工作的背景,但第二個之後第一個完成會被執行,檢查此link
  • 移動onMapReady的某些部分onPostExecute,類似下面

移動

@Override 
    protected void onPostExecute(String types) { 
     if (types.equalsIgnoreCase("distance")) { 
      disRes = GMapsDistanceResponseJSONDeserializer.deserialize(jsonString); 
     }if (types.equalsIgnoreCase("directions")) { 
      dirRes = GMapsDirectionsResponseJSONDeserializer.deserialize(jsonString); 
      String points = dirRes.getRoutes().get(0).getOverviewPolyline(); 
      List<LatLng> list = PolyUtil.decode(points); 
      googleMap.addPolyline(new PolylineOptions() 
      .geodesic(false) 
      .addAll(list) 
      .color(Color.RED) 
      .width(25) 
     ); 
     } 
    } 
0

AsyncTask.SERIAL_EXECUTOR用於強制AsyncTask在串行時尚中執行。

對於你的情況更多的是一個小竅門將完成這項工作。

  1. 爲相同的AsyncTask創建回調並傳遞不同的參數來區分函數。

  2. 現在在第二次回調中發起mapFragment.getMapAsync(this);


public class MainFragment ... 
{ 
    DataDownloader dataDownloader; 
    int processCount=1; 


    void initiateProcessFirst(){ 
     new DataDownloader(this,processCount).execute(); 
    } 
    public void initiateSecondProcess(){ 
     processCount++; 
     new DataDownloader(this,processCount).execute(); 
    } 


    public void secondProcessCompleted(){ 
      mapFragment.getMapAsync(this); 
    } 
    } 

的AsyncTask邏輯是這樣的下面

public class DataDownloader extends AsyncTask<Void,Void,Boolean> { 

    MainFragment context; 
    int processCount; 
    public DataDownloader(MainFragment context ,int processCount){ 
     this.context=context; 
     this.processCount=processCount; 

    } 
    @Override 
    protected Boolean doInBackground(Void... params) { 
     boolean status=false; 
     // Do logic according to the Process Count 

     return status; 
    } 

    @Override 
    protected void onPostExecute(Boolean aBoolean) { 
     super.onPostExecute(aBoolean); 
     if(processCount==1) 
      context.initiateSecondProcess(); 
     else 
      context.secondProcessCompleted(); 
    } 
} 
相關問題