HTTP HTTP requests to run in the simulator but not on the device

I'm making a simple Android Wear app to control my thermostats, and I'm sending POST requests from Volley to control them. Everything works fine in the Android Wear simulator (the request works), but while the application is loading on my Moto 360, the volleyball request is called, but the time runs out invariably.

Why can my volleyball request not work on my watch, but work with a simulator? Requests for other applications were successful on my watch (for example, the built-in weather application can download weather data in about 3 seconds). And the strangest part: I had an application running (successfully executing volleyball requests) on my watch, and about a day after I installed it on my watch from Android Studio, it suddenly stopped downloading data for no apparent reason.

What I have tried so far:

  • I requested permission for the web in manifest.xml .
  • I increased the timeout to 30 seconds (see my code below), which didn't change anything.
  • I tried to connect my computer and simulator to my telephone connection via Bluetooth (in order to play back the Bluetooth connection that my physical watch has on my phone), and the simulator successfully completed the request (albeit with a two-second delay), excluding the possibility of Bluetooth running too slow.
  • I made sure that the API level is low enough for my watch in Marshmallow (my watch and app are both API 23 levels).
  • I tried to execute a quick check request on Google before requesting the company’s servers with the data of my thermostat, and while the Google request returns the HTML code of the site in the simulator, it occasionally appears on my watch (it is initiated thirty seconds after the request) .
  • I tried to put some dummy data into the recycler view data that should be loaded, and the dummy data really appeared, which caused the recycler view to fail.
  • I removed the application from my watch and reinstalled it, and uninstalled the companion from my phone, reinstalled it and deleted it again, all to no avail.
  • A long chat with Google didn’t bring anything meaningful.

Here is my code (from my main adapter):

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

, which is called from the onCreate() method in my main activity using this code:

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

If you want to view the logs created by running this in the simulator and on the watch, they are on Google Drive here .


Edit 1:. Rebooting my watch temporarily fixes the problem and allows the watch to make HTTP requests again, but it breaks again when the watch disconnects from Bluetooth, connects to WiFi, disconnects from WiFi, and reconnects to Bluetooth (so it breaks every time I switch through my apartment without a phone, and then come back).

Edit 2:. I switched volleyball requests to all HTTPURLConnection requests in the Async stream, and the same problems arise as volleyball.


tl; dr: My application Volleyball requests work in the simulator, but not on my Android Wear watch anymore (although similar requests for Play-downloaded applications work), how can I get a volley to ask to work again in my application on the watch?

+5
source share
4 answers

According to these two conversations below, it seems that the WiFi connection allows Android Wear to connect to the phone via WiFi, rather than directly to the Internet. However, Android Wear 2.0 allows you to use the usual network APIs.

Direct Internet connection on Android Wear?

Does Android Wear support direct Internet access?

So, for Android Wear 2.0+ Volley requests from wearing the app should work.

If you want to use Android Wear <2.0, then:

In the media, in onCreate() add a key that indicates whether the phone should begin collecting data.

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

On the phone, in onDataChanged , check if the media wants to start collecting data. If so, start the Volley request.

 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 } } 

Then your Volley onResponse request should pass the data back to 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); } 

Finally, you can access the data in Wearable using onDataChanged and save it in your model for transferring it to the adapter:

 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 } } 

You will need Wearable.API to implement this, and your class must implement DataApi.DataListener . For more information, see Accessing Wearable Data Layer and Synchronizing Data Elements.

Hope this helps.

+1
source

I also use volley on the Android application that I created, and I run it on the Moto 360, I encountered the same problem a couple of times. Try rebooting your device. Go to Settings> Reboot. That sounds silly, but it worked for me.

+2
source

You can try an alternative to volleyball if you can eliminate the connection as a problem:

 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' 

Important versions.

Then at your request:

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

Then just execute your code from thread / synthetics / ask it to linger a bit.

Edit: Just in case, there is a problem with adding a map:

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

Also, as another note, be sure to change the return type from void to both of these methods on Map

+1
source

This is not the case when the watch is connected to the phone via Bluetooth, the Internet will not work, since Wi-Fi is disabled. If the watch uses Wi-Fi to connect to the phone, it will work.

I am working on wearing a 2.0 application and just turn off the pin on my phone so that my watch can connect to the Internet.

0
source

Source: https://habr.com/ru/post/1263113/


All Articles