Android HTTP请求在模拟器中工作但不在磨损设备上

owl*_*ipe 5 java android android-volley wear-os

我正在制作一个简单的Android Wear应用来控制我的恒温器,我正在用Volley发送POST请求来控制它们.Android Wear模拟器中的一切都运行良好(请求有效),但是,当应用程序在我的Moto 360上加载时,凌空请求被调用,但总是超时.

为什么我的截击请求会在我的手表失败但是在模拟器上工作?其他应用程序的请求在我的手表上成功(例如,内置天气应用程序可以在大约3秒内加载天气数据).而且,最奇怪的部分:我的应用程序在我的手表上工作(成功发出截击请求),并且,在我从Android Studio安装到我的手表大约一天之后,它突然停止加载数据,原因并非明显.

到目前为止我尝试过的:

  • 我已经请求了我的互联网许可manifest.xml.
  • 我已将超时时间增加到30秒(请参阅下面的代码),这并没有改变任何内容.
  • 我试过通过蓝牙将我的计算机和模拟器连接到手机的连接上(将我的物理手表的蓝牙连接复制到我的手机上),模拟器仍然成功地提出请求(虽然延迟了两秒),排除了蓝牙太慢的可能性.
  • 我确保API级别足够低,以便我的Marshmallow运行手表(我的手表和应用程序都是API级别23).
  • 在我使用恒温器数据向公司服务器发出请求之前,我尝试向Google做一个快速测试请求,当Google请求在模拟器中返回网站的HTML代码时,它会在我的手表上超时(请求启动后30秒) .
  • 我尝试将一些虚拟数据放入应该加载的回收器视图数据中,并且虚拟数据确实显示出来,排除了回收器视图被破坏.
  • 我从手表中删除了该应用并重新安装了该应用,并从手机中删除了该手机,重新安装并再次将其删除,但都无济于事.
  • 与Google支持人员进行长时间的聊天并没有产生任何意义.

这是我的代码(来自我的主视图的适配器):

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);
    }
Run Code Online (Sandbox Code Playgroud)

onCreate()使用以下代码从我的主活动中的方法调用:

RequestQueue queue = Volley.newRequestQueue(this);
refreshThermostatsRecyclerView(queue);
Run Code Online (Sandbox Code Playgroud)

如果您想在模拟器和手表中查看通过运行创建的日志,则可以在此处查看Google云端硬盘.


编辑1:重新启动我的手表会暂时解决问题并允许手表再次发出HTTP请求,但一旦手表断开蓝牙连接,连接到WiFi,断开WiFi连接并重新连接到蓝牙(它会中断我没有电话的情况下穿过我的公寓,然后返回).

编辑2:我将乱序请求全部切换到异步线程中的HTTPURLConnection请求,并且出现与volley相同的问题.


tl; dr:我的应用程序的Volley请求正在模拟器中工作,但不再在我的Android Wear手表上工作(虽然Play商店下载的应用程序的类似请求有效),如何在我的手表上的应用程序上再次获得凌空请求?

Bha*_*aSW 2

根据下面的这两个对话,WiFi 连接似乎只允许 Android Wear 通过 WiFi 连接到手机,而不能直接连接到互联网。但是,Android Wear 2.0 允许您使用常规网络 API。

Android Wear 上可以直接连接互联网吗?

Android Wear 支持直接访问互联网吗?

因此,对于 Android Wear 2.0+,Volley来自可穿戴应用程序的请求应该可以工作。

如果您想使用Android Wear <2.0,那么:

在可穿戴设备上,onCreate()添加一个键来指示手机是否应该开始收集数据。

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

在手机上,onDataChanged检查可穿戴设备是否要开始收集数据。如果是,则开始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
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后,您的Volley请求onResponse应该将数据传递回可穿戴设备。

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

 }
Run Code Online (Sandbox Code Playgroud)

最后,您可以使用访问可穿戴设备中的数据onDataChanged并将其存储在模型中以将其传递到适配器:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

您需要Wearable.API实现这个,并且您的类应该实现DataApi.DataListener. 有关入门的更多信息,请参阅访问可穿戴数据层同步数据项

希望这可以帮助。