2016-08-16 74 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(); 
    } 
} 
相关问题