How to execute onMapReady() callback after all the AsyncTasks are completed?

放肆的年华 提交于 2020-01-23 04:18:28

问题


I am having trouble with my code where i have my Activity which i use to call google api's and retrieve jsons, deserialize them and use it's Polylines to draw on the map.

The problem is that getMapAsync() which sends the callback for onMapReady() (which is used to create the map) is executed immediately after executing my Async Tasks which retrieves necessary data to create the map.

How can i make this happen without stopping the UI thread? I tried doing this calling .execute.get() which freeze the UI thread. But if i do that, i won't be able to use ProgressDialog to inform the users about the delay for fetching data from the servers, which they will be exposed to a frozen UI until the task is complete. How can i do this?

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();
}

}

回答1:


Quick and somewhat dirty solution would be to execute both AsyncTasks on a single AsyncTask and then on its onPostExecute code invoke getMapAsync. this way you will be sure your tasks finished before you dealing with map's readyness.




回答2:


  • Firstly, run tasks after onMapReady because you will get rid of concern of ready map.
  • Your async tasks are not parallel, they working on background but second one will be executed after first one completed, check this link
  • Move some parts of onMapReady to onPostExecute, something like below

Move

  @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)
          );
      }
  }



回答3:


AsyncTask.SERIAL_EXECUTOR is used to force AsyncTask to execute in Serial Fashion.

More over for your case a little trick will do the job.

  1. Create call back for same AsyncTask and pass different parameters to differentiate the functions.

  2. Now in the second call back initiate 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 Logic goes like the below

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();
    }
}


来源:https://stackoverflow.com/questions/38971038/how-to-execute-onmapready-callback-after-all-the-asynctasks-are-completed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!