Rendimiento de clase de URL – Invalid_Request with next_page_token

En mi aplicación de Android el usuario puede seleccionar categorías (café, restaurante, …) de los lugares que quiere ver.

Obtengo el resultado de google-places-api con un next_page_token, cuando uso la url siguiente:

https://maps.googleapis.com/maps/api/place/textsearch/json?query=cafe+in+Elfde-Liniestraat%2C+Hasselt%2C+Belgium&pagetoken=ClRHAAAAqYa7IpwMQH3q1DyinfsMnkuOaZg8wQrp0pvzarv13pwqruqT2YfaEry6v_d-L4d_TC13G6iHuPz-rc1KbI6XRE01rB5CuXcHISu-CI_CaKESEMUxSjHhHDNee4xbr2tPEZcaFPvO6xlRDjs-5AixyD9vamWwTGlU&sensor=true&key=<mykey> 

O esta url:

 https://maps.googleapis.com/maps/api/place/textsearch/json?pagetoken=ClRHAAAAqYa7IpwMQH3q1DyinfsMnkuOaZg8wQrp0pvzarv13pwqruqT2YfaEry6v_d-L4d_TC13G6iHuPz-rc1KbI6XRE01rB5CuXcHISu-CI_CaKESEMUxSjHhHDNee4xbr2tPEZcaFPvO6xlRDjs-5AixyD9vamWwTGlU&sensor=true&key=<mykey> 

Recibo un INVALID_REQUEST.

Este es el código que utilizo para ejecutar y obtener los resultados:

 @Override protected ArrayList<String> doInBackground(String... params) { // When more then one category is selected, this character needs to be after it. final String DELIMITINGCHARACTER = "|"; // Add all the categories to a variable to put later on in the URL. String myTypes = ""; for (String category : params){ // A category must be lowercase letters only. category = category.toLowerCase(); // A category may not display a whitespace. // The whitespace(s) must be replaced with a '_'. category = category.replaceAll(" ", "_"); myTypes += category + DELIMITINGCHARACTER; } // Delete if the string ends with the delimitingcharachter the delimitingcharacter! if (myTypes.endsWith("|")){ myTypes = myTypes.substring(0, myTypes.length() - 1); } ArrayList<String> myPointsOfInterest = new ArrayList<String>(); try{ String urlString; String urlData; //String urlApi = "&sensor=true&key=<myKey>"; // Key 1 String urlApi = "&sensor=true&key=<myKey>"; // Key 2 if (_txtFindLocation.getText().length() > 0){ urlString = "maps.googleapis.com/maps/api/place/textsearch/json?"; urlData = "query=" + URLEncoder.encode(myTypes, "UTF-8") + "+in+" + URLEncoder.encode(_txtFindLocation.getText().toString(), "UTF-8"); } else{ urlString = "maps.googleapis.com/maps/api/place/search/json?"; urlData = "location=" + _myCurrentPosition.getLatitudeE6() / 1e6 + "," + _myCurrentPosition.getLongitudeE6() / 1e6 + "&radius=5000&types=" + URLEncoder.encode(myTypes, "UTF-8"); } ArrayList<String> myJsonString = new ArrayList<String>(); myJsonString.add(getDataOfUrl(urlString, urlData, urlApi, null)); for (String jsonString : myJsonString){ // Turn String into a JSON Object. JSONObject jsonPredictionsObject = new JSONObject(jsonString); String urlToken = jsonPredictionsObject.optString("next_page_token"); if (urlToken != ""){ myJsonString.add(getDataOfUrl(urlString, urlData, urlApi, "&pagetoken=" + urlToken)); } } Log.d("MainActivity", "size of myJsonString " + String.valueOf(myJsonString.size())); for (String jsonString : myJsonString){ Log.d("MainActivity", jsonString); // Turn String into a JSON Object. JSONObject jsonPredictionsObject = new JSONObject(jsonString); // Get a JSON Array that is inside the JSON Object. JSONArray jsonPredictionsArray = jsonPredictionsObject.getJSONArray("results"); for (int i = 0; i < jsonPredictionsArray.length(); i++){ jsonPredictionsObject = (JSONObject) jsonPredictionsArray.get(i); final String name = jsonPredictionsObject.getString("name"); final String vicinity = jsonPredictionsObject.optString("vicinity").compareTo("") != 0 ? jsonPredictionsObject.optString("vicinity") : jsonPredictionsObject.optString("formatted_address"); final JSONObject geometryObject = jsonPredictionsObject.getJSONObject("geometry"); final JSONObject locationObject = geometryObject.getJSONObject("location"); final JSONArray typesArray = jsonPredictionsObject.getJSONArray("types"); final double latitude = locationObject.getDouble("lat"); final double longitude = locationObject.getDouble("lng"); String types = ""; for (int t = 0; t < typesArray.length(); t++){ String type = typesArray.getString(t); type = type.toLowerCase(); type = type.replaceAll("_", " "); types += type + " - "; } types = types.substring(0, types.length() - 2); myPointsOfInterest.add(String.valueOf(latitude) + DELIMITINGCHARACTER + String.valueOf(longitude) + DELIMITINGCHARACTER + types + DELIMITINGCHARACTER + name + DELIMITINGCHARACTER + vicinity); } } } catch (IOException e){ Log.e("Search points of interest", "GetPointsOfinterest: doInBackGround", e); } catch (JSONException e){ Log.e("Search points of interest", "GetPointsOfinterest: doInBackGround", e); } return myPointsOfInterest; } public String getDataOfUrl(String urlString, String urlData, String urlApi, String urlToken){ try{ URL myURL; if (urlToken == null) { myURL = new URL("https://" + urlString + urlData + urlApi); } else { Log.d("URL INPUT", "https://" + urlString + urlData + urlToken + urlApi); myURL = new URL("https://" + urlString + urlData + urlToken + urlApi); } URLConnection myURLConnection = myURL.openConnection(); BufferedReader myBufferReader = new BufferedReader(new InputStreamReader(myURLConnection.getInputStream())); String strLine; StringBuffer strBuffer = new StringBuffer(); // Take Google's legible JSON and turn it into on big String. while((strLine = myBufferReader.readLine()) != null){ strBuffer.append(strLine); } Log.d("URL OUTPUT", strBuffer.toString()); return strBuffer.toString(); } catch (IOException e){ Log.e("getDataOfUrl", "Error: ", e); } return null; } 

Esta es la salida de logcat:

 11-03 14:47:13.832: D/URL OUTPUT(19532): { "html_attributions" : [], "next_page_token" : "ClRHAAAAqYa7IpwMQH3q1DyinfsMnkuOaZg8wQrp0pvzarv13pwqruqT2YfaEry6v_d-L4d_TC13G6iHuPz-rc1KbI6XRE01rB5CuXcHISu-CI_CaKESEMUxSjHhHDNee4xbr2tPEZcaFPvO6xlRDjs-5AixyD9vamWwTGlU", "results" : [ { "formatted_address" : "Meldertstraat 42, Hasselt, België", "geometry" : { "location" : { "lat" : 50.9311660, "lng" : 5.3423240 } }, "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/cafe-71.png", "id" : "e6ba73e5b439dddb83aaefc94c71954da0cb0268", "name" : "Café Café", "rating" : 4.40, "reference" : "CnRpAAAAdVZpUI4NKwsAiQTOjbYG9psNbU7awZkS6_8Ee4r3AvCKhpqWeiDqdof7zYmoUZWKj0A8rOwtncSa1YFVNNo6RxFmmHvuNdWCaucTqkuSSDw8E2o0pf5E6EiMj-7-Hd5xBzDtC0j9d5lLcVWW3AQy1xIQRwgfWwrZkyK65blCeGqhFhoUB9kTW5QVD9sNNuF75MvVewYTcxA", "types" : [ "cafe", "food", "establishment" ] }, { "formatted_address" : "Kempischesteenweg 27, Hasselt, België", "geometry" : { "location" : { "lat" : 50.9350770, "lng" : 5.3397760 } }, "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/cafe-71.png", "id" : "dc66d311b3c4f5d1a87d5959dfdbc7616ad10b24", "name" : "Oberonn", "opening_hours" : { "open_now" : true }, "reference" : "CnRlAAAA5q-rz_aOTWsFGQIJz_6zyLbXIczXOTq4PVFxniOjxsCwnw7uIfY8tu7Jk-QbJ-arMWgdClnSpX28q2SqxD8021LGWcaf4Sgo9MaXWpoD6c4TSagyVO9_l_HUXgMoOFJzhHG_NH6z-t1DPxT1zD19PhIQ2gBP9cLazKeB96ZDTpFdsxoUVGB2Ddhrq6JUoTJgrHGL-SINOWk", "types" : [ "cafe", "food", "establishment" ] }, { "formatted_address" : "Willekensmolenstraat 41, Hasselt, België", "geometry" : { "location" : { "lat" : 50.9316830, "lng" : 5.3470750 } }, "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/cafe-71.png", "id" : "04937541c2bf71ebec7ac13d506dbbd2727e1ce3", "name" : "Den Drossaerd", "reference" : "CnRqAAAA0cPmuMx0_J4x-o-yn0oT1D3kD-IHYAQPotAPPeDD3DWh2FXkD89kCsYoUGDLBlH2mKY6ju18JyCHvc4W_izLcd6TUOIoXrbUCyrtxOL4sTAFb41kH1aFT4dOBgvigYrGIcV8Qbzq-K4YGL3t7pnf1hIQKmUp-LLqtGHb4waYi2nq8hoU3VgwykpytoSUUPe2Ue1HmPrMRtE", "types" : [ "cafe", "food", "establishment" ] }, { "formatted_address" : "Leopoldplein 1, Hasselt, België", "geometry" : { "location" : { "lat" : 50.9275810, "lng" : 5.3363830 } }, "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/lodging-71.png", "id" : "cc30d6f4e6b0db1ed6dfd17bac118bbf78f194ae", "name" : "Century (Hotel)", "rating" : 3.80, "reference" : "CnRsAAAAfw4ucOBllDjMCtRU9epYQelpKHRx3u8JR8jr4I5jFzJsktNn3Un-3LjKKWtXCk3Unofi_6RhPFw9Tp8VU_Z7i-WOa00P-pirtCDjQPxg7sp470Mgh6_6PQspGG39H3k-VIMuUz9HWmoP3sPjump6SRIQTp1LZghfi-_HVaMfQArGPxoU-6ogK2IGMiueMEXP9mFiHlGJmo8", "types" : [ "lodging", "establishment" ] }, { "formatted_address" : "Maastrichterstraat 30, Hasselt, België", "geometry" : { "location" : { "lat" : 50.9295410, "lng" : 5.3391230 } }, "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/cafe-71.png", "id" : "352f9da4642588aba419353487b210baeb30ddd3", "name" : "In De Kleine Hal", "reference" : "CnRuAAAAAlnMpdiL4Kluiw1T0-QgKWFv9wwWvrSY4w-B7SLI7gvpqT0FYaMTl6DhxncPLqRyxOTWxw3DP3r1XvNHDKXnAb3eRM-gZYwIqbvzVq62zEZgGw0usQgf48mAWOrDpegdNLnEFRYkIduRwlDMDyIOyBIQlDs9BozH4m_gE-dZKZf7yxoUqw0H_HT_IQnLaVm0YwG1QV7o3kg", "types" : [ "cafe", "food", "establishment" ] }, { "formatted_address" : "Fruitmarkt 32, Hasselt, België", "geometry" : { "location" : { "lat" : 50.9299760, "lng" : 5.3393550 } }, "icon" : "http://maps.gstatic.com/mapfiles 11-03 14:47:13.864: D/URL INPUT(19532): https://maps.googleapis.com/maps/api/place/textsearch/json?query=cafe+in+Elfde-Liniestraat%2C+Hasselt%2C+Belgium&pagetoken=ClRHAAAAqYa7IpwMQH3q1DyinfsMnkuOaZg8wQrp0pvzarv13pwqruqT2YfaEry6v_d-L4d_TC13G6iHuPz-rc1KbI6XRE01rB5CuXcHISu-CI_CaKESEMUxSjHhHDNee4xbr2tPEZcaFPvO6xlRDjs-5AixyD9vamWwTGlU&sensor=true&key=<myKey> 11-03 14:47:13.989: D/URL OUTPUT(19532): { "html_attributions" : [], "results" : [], "status" : "INVALID_REQUEST"} 

PS: Cuando pasé el código en mi navegador (con next_page_token) ambas maneras son correctas, sólo que mi aplicación para Android no recibo datos válidos. Y sí tengo una llave de la API, pero la quité aquí del código y de mi salida del logcat.

Alguien una idea de lo que estoy haciendo mal aquí?

EDITAR Cuando hardcode mi url (con next-page-token) en Android, y afterwords dejarlo correr. Recibo los datos que esperaba, por lo que no Invalid_Request se devuelve. Los problemas se encuentra en algún lugar en la construcción de la url en Android, o el uso de la clase URL.

Encontré la respuesta en mi propia pregunta: después de un tiempo, sólo necesitaba comprobar mi salida de logcat mejor.

Los tiempos de la solicitud en tiempos en que los datos fueron enviados de regreso de google.

  • Tiempo de salida de la solicitud 1: 14: 47: 13: 832

  • Tiempo de entrada de la solicitud 2: 14: 47: 13: 864

  • Tiempo de salida de la solicitud 2: 14: 47: 13: 989

Estos tiempos son cerca de uno al otro, en mi opinión Google pensaba que yo era un spammer / hacker o algo así y me denegó el acceso al servidor en la segunda solicitud.

La solución para mí es esperar 1 segundo si hay un next_page_token y luego enviar la solicitud de seguimiento.

  • Mueva un marcador entre 2 coordenadas siguiendo las instrucciones de manejo
  • Estadísticas de Servicios de Google Play
  • Android 8 o superior: comprobar los servicios de Google Play
  • Cómo mostrar la animación de ondulación en google map en Android?
  • Google Maps v2 Error de autorización. Diferentes SHA1
  • Algoritmo de Google Maps
  • En google maps V2 ... fragment.getMap () devuelve null
  • ¿Se aplican los límites API de Google Maps a las aplicaciones de Android?
  • Reemplazar getMap con getMapAsync
  • Android "No se pudo encontrar el estilo 'mapViewStyle' en el tema actual" error
  • Utilidad de mapas de Android: imágenes de la URL
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.