Solicitudes HTTP de Android que funcionan en el simulador, pero no en dispositivo de uso

Estoy haciendo una sencilla aplicación Android Wear para controlar mis termostatos, y estoy enviando solicitudes POST con Volley para controlarlas. Todo funciona bien en el simulador de Android Wear (la solicitud funciona), pero, mientras la aplicación se carga en mi Moto 360, la solicitud de volea se llama, pero invariablemente se agota.

¿Por qué mi solicitud de volea fallaba en mi reloj pero estaba trabajando en el simulador ? Las solicitudes de otras aplicaciones tienen éxito en mi reloj (por ejemplo, la aplicación de tiempo incorporada puede cargar datos meteorológicos en aproximadamente 3 segundos). Y, la parte más rara: Tenía la aplicación funcionando (con éxito haciendo solicitudes de volea) en mi reloj, y, un día después de que lo instalé en mi reloj de Android Studio, de repente dejó de cargar datos sin razón aparente.

Lo que he probado hasta ahora:

  • He solicitado el permiso de Internet en mi manifest.xml .
  • He aumentado el tiempo de espera a 30 segundos (ver mi código a continuación), que no cambió nada.
  • He intentado amarrar mi computadora y el simulador a la conexión de mi teléfono vía Bluetooth (para replicar la conexión de Bluetooth mi reloj físico tiene a mi teléfono), y el simulador hizo la petición con éxito todavía (aunque con un retraso de dos segundos) La posibilidad de que Bluetooth sea demasiado lento.
  • Me aseguré de que el nivel de API es lo suficientemente bajo para mi reloj Marshmallow-running (mi reloj y la aplicación son ambos de nivel API 23).
  • Intenté hacer una rápida solicitud de prueba a Google antes de la solicitud a los servidores de la compañía con mis datos del termostato, y mientras la solicitud de Google devuelve el código HTML del sitio en el simulador, se agota en mi reloj (treinta segundos después de iniciada la solicitud) .
  • Traté de poner algunos datos ficticios en la vista del reciclador que se deben cargar los datos, y los datos ficticios aparecieron, descartando que la vista del reciclador esté rota.
  • He eliminado la aplicación de mi reloj y lo he reinstalado, y eliminado el compañero de mi teléfono, reinstalado, y eliminado de nuevo, todo sin éxito.
  • Una larga conversación con el Soporte de Google no produjo nada significativo.

Aquí está mi código (desde el adaptador de mi vista principal):

 public void refreshThermostatsRecyclerView(RequestQueue queue) { String url = "https://mobile.skyport.io:9090/login"; // login call to the thermostats server Skyport Log.w("myApp", "Starting /login call to Skyport"); // this gets called on simulator and watch // Request a string response from the provided URL. StringRequest stringRequest = new StringRequest(Request.Method.POST, url, Response.Listener<String>() { @Override public void onResponse(String response) { // Display the response string. Log.w("myApp", "Response is: " + response); // this gets called on the simulator but not the watch try { // there's some code to parse the data. } catch (JSONException e) { Log.w("myApp", "catching an error parsing the json."); // never gets called. e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.w("myApp", "Skyport request didn't work! " + error); // this always gets called on the watch, with the error being a timeout error (com.Android.Volley.timeouterror) but never gets called in the simulator } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> m = new HashMap<>(); m.put("Referer", "app:/VenstarCloud.swf"); // here I put some more headers return m; } @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> m = new HashMap<>(); m.put("version", "3.0.5"); m.put("email", userEmail); m.put("password", userToken); return m; } }; // Add the request to the RequestQueue. int socketTimeout1 = 30000; // times out 30 seconds after the request starts on the watch RetryPolicy policy1 = new DefaultRetryPolicy(socketTimeout1, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); stringRequest.setRetryPolicy(policy1); queue.add(stringRequest); } 

Que se llama desde el método onCreate() en mi actividad principal con este código:

 RequestQueue queue = Volley.newRequestQueue(this); refreshThermostatsRecyclerView(queue); 

Si quieres ver los registros creados al ejecutarlo en el simulador y en el reloj, están en Google Drive aquí .


Editar 1: Una reinicialización de mi reloj corrige el problema temporalmente y permite que el reloj vuelva a hacer peticiones HTTP, pero se rompe una vez que el reloj se desconecta de Bluetooth, se conecta a WiFi, se desconecta de WiFi y se vuelve a conectar a Bluetooth Tiempo voy por mi apartamento sin mi teléfono y luego regreso).

Editar 2: Cambié las solicitudes de volea a HTTPURLConnection Requests en un hilo Async, y los mismos problemas ocurren como con volley.


Tl; dr: Las solicitudes de Volley de mi aplicación están funcionando en el simulador pero no en mi reloj Android Wear (aunque las solicitudes similares a Play Store-descargadas funcionan), ¿cómo puedo obtener una solicitud de volley para volver a trabajar en mi aplicación en el reloj? ?

Según estas dos conversaciones a continuación, parece que la conectividad WiFi sólo permite que Android Wear se conecte a un teléfono a través de WiFi y no directamente a Internet. Sin embargo, Android Wear 2.0 le permite usar APIs de red regulares.

¿Conexión directa a Internet en Android Wear?

¿Soporta Android Wear el acceso directo a Internet?

Por lo tanto, para Android Wear 2.0+ Volley solicitudes de aplicación portátil debería funcionar.

Si desea utilizar Android Wear <2.0, entonces:

On Wearable, en onCreate() agrega una clave que indica si el teléfono debe comenzar a recopilar datos.

 PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/shouldStart"); putDataMapReq.getDataMap().putBoolean(SHOULD_START_KEY, true); PutDataRequest putDataReq = putDataMapReq.asPutDataRequest(); PendingResult pendingResult = Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq); 

En el teléfono, en onDataChanged , compruebe si usable quiere empezar a recopilar datos. Si es así, comience la solicitud de Volley .

 for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_CHANGED) { // DataItem changed DataItem item = event.getDataItem(); if (item.getUri().getPath().compareTo("/shouldStart") == 0) { DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap(); boolean shouldStart = dataMap.getBoolean(SHOULD_START_KEY)); if(shouldStart) { Volley.newRequestQueue(this).add(request); } } } else if (event.getType() == DataEvent.TYPE_DELETED) { // DataItem deleted } } 

Entonces, onResponse su petición de onResponse debe pasar los datos a Wearable.

 public void onResponse(String response) { PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/data"); putDataMapReq.getDataMap().putString(DATA_KEY, true); PutDataRequest putDataReq = putDataMapReq.asPutDataRequest(); PendingResult pendingResult = Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq); } 

Finalmente, puede acceder a los datos de su Wearable usando onDataChanged y almacenarlos en su modelo para pasarlos al adaptador:

 for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_CHANGED) { // DataItem changed DataItem item = event.getDataItem(); if (item.getUri().getPath().compareTo("/data") == 0) { DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap(); parseAndpassToAdapter(dataMap.getString(DATA_KEY)); } } else if (event.getType() == DataEvent.TYPE_DELETED) { // DataItem deleted } } 

Usted necesitará Wearable.API para implementar esto y su clase debe implementar DataApi.DataListener . Para obtener más información al iniciar, consulte Acceso a la capa de datos utilizables y sincronización de elementos de datos

Espero que esto ayude.

También estoy usando volley en una aplicación de desgaste de Android que he construido y lo estoy ejecutando en un Moto 360, me he encontrado con el mismo problema un par de veces. Intente reiniciar el dispositivo. Vaya a Configuración> Reiniciar. Suena tonto, pero ha funcionado para mí.

Usted podría intentar una alternativa a la volea si puede descartar la conexión como el problema:

 compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:support-v4:23.1.0' compile 'com.android.support:design:23.1.0' compile 'com.google.code.gson:gson:2.2.4' compile 'com.google.api-client:google-api-client:1.20.0' 

Las versiones son importantes.

A continuación, a su solicitud:

 Map<String, String> contentParams = new HashMap<>(); InputStream is = null; NetHttpTransport transport = null; HttpRequest request = null; HttpResponse resp = null; HttpHeaders headers = new HttpHeaders(); JSONObject json = null; try { transport = new NetHttpTransport(); HttpRequestFactory factory = transport.createRequestFactory(); request = factory.buildPostRequest(new GenericUrl(url), null); contentParams = getContentParameters(); headers.putAll(getHeaderParameters()); request.setHeaders(headers); request.getUrl().putAll(contentParams); resp = request.execute(); is = resp.getContent(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (is != null) { string = getJSONFromInputStream(is); json = new JSONObject(string); } } catch (Exception e) { e.printStackTrace(); } } transport.shutdown(); protected Map<String, String> getContentParameters() { Map<String, String> m = new HashMap<>(); m.put("version", "3.0.5"); m.put("email", userEmail); m.put("password", userToken); return m; } protected Map<String, String> getHeaderParameters() { Map<String, String> m = new HashMap<>(); m.put("Referer", "app:/VenstarCloud.swf"); return m; } protected String getJSONFromInputStream(InputStream is) { if (is == null) throw new NullPointerException(); //instantiates a reader with max size BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8 * 1024); StringBuilder sb = new StringBuilder(); try { //reads the response line by line (and separates by a line-break) String line; while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { //closes the inputStream is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } 

Entonces apenas ejecuta su código de un hilo / asynctask / lo tiene retrasa su frente ligeramente

Editar: Sólo en caso de que haya un problema con la adición de un mapa:

 for (Entry<String, String> entry : getHeaderParameters()) { headers.put(entry.getKey(), entry.getValue()); } for (Entry<String, String> entry : getContentParameters()) { request.getUrl().put(entry.getKey(), entry.getValue()); } 

También como otra nota, asegúrese de cambiar el tipo de retorno de void en ambos métodos a Mapa

¿No es esto sólo el caso de cuando el reloj está conectado al teléfono a través de bluetooth el Internet no funcionará, como Wi-Fi está apagado. Si el reloj está utilizando wifi para conectarse al teléfono, entonces funcionará.

Estoy trabajando en la aplicación de desgaste 2.0 y simplemente apague blueooth en mi teléfono para mi reloj para obtener conexión a Internet.

  • No se puede instanciar la clase: android.support.v7.widget.SearchView
  • Dibujo ShapeRenderer transparente en libgdx
  • ¿Cómo puedo bloquear archivos en android usando código java?
  • Recuperar Contexto de un fragmento
  • ¿Una clave API de Google Maps caduca después de un tiempo determinado?
  • Botón personalizado en la barra de título del cuadro de diálogo
  • Cajón de navegación onNavigationDrawerItemSelected llamado antes de MainActivity onCreate?
  • Notificando un solo hilo: notify, notifyAll o concurrent.locks.Condition?
  • "El inicio de la etiqueta no está cerrado" al comentar dentro de la etiqueta de inicio y fin del elemento XML
  • Cómo hacer que el movimiento de caída de nieve para un mapa de bits en Android
  • Publicar el parámetro en el archivo PHP
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.