首页 文章

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

提问于
浏览
5

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

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

What I've tried so far:

  • 我在 manifest.xml 中请求了Internet权限 .

  • 我已将超时时间增加到30秒(请参阅下面的代码),这并没有改变任何内容 .

  • 我试过通过蓝牙将我的电脑和模拟器连接到我手机的连接上(将我的物理 Watch 的蓝牙连接复制到我的手机上),模拟器仍然成功地提出了请求(尽管有两秒的延迟),判决蓝牙太慢的可能性 .

  • 我确保API级别足够低,以便我的Marshmallow运行 Watch (我的 Watch 和应用程序都是API级别23) .

  • 我尝试在向模拟器中的公司's servers with my thermostat data, and while the Google request returns the site'的HTML代码发出请求之前向Google做一个快速测试请求,它在我的 Watch 上超时(请求启动后30秒) .

  • 我尝试将一些虚拟数据放入回收器视图中,应该加载数据,并且虚拟数据确实显示出来,排除了回收器视图被破坏 .

  • 我从 Watch 中删除了该应用并重新安装了该应用,并从我的手机中删除了该手机,重新安装并再次将其删除,但都无济于事 .

  • 与Google支持人员进行冗长的聊天并没有产生任何有意义的信息 .

Here's my code (from my main view's 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'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);
    }

Which is called from the onCreate() method in my Main Activity with this code:

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

如果你'd like to view the logs created by running this in the simulator and on the watch, they'重新on Google Drive here .


Edit 1: 重新启动我的 Watch 会暂时解决问题,并允许 Watch 再次发出HTTP请求,但一旦 Watch 断开蓝牙连接,连接到WiFi,断开WiFi连接并重新连接到蓝牙,它就会再次中断(所以每次我都会断开)没有我的电话去我的公寓,然后返回) .

Edit 2: 我在异步线程中将截击请求全部切换到HTTPURLConnection请求,并且出现与volley相同的问题 .


tl;dr: 我的应用程序's Volley requests are working in the simulator but not on my Android Wear watch anymore (though Play Store-downloaded apps'类似的请求工作),如何在 Watch 上的应用程序上再次使用截击请求?

4 回答

  • 0

    我也在我制作的Android磨损应用程序上使用凌空,我在Moto 360上运行它,我遇到了同样的问题几次 . 尝试重新启动设备 . 转到设置>重新启动 . 这听起来很傻但它对我有用 .

  • 1

    根据以下这两个对话,似乎WiFi连接仅允许Android Wear通过WiFi连接到手机而不是直接连接到Internet . 但是,Android Wear 2.0允许您使用常规网络API .

    Direct internet connection on Android Wear?

    Does Android Wear support direct access to the Internet?

    因此,对于Android Wear 2.0,来自可穿戴应用程序的请求应该有效 .

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

    在Wearable上,在 onCreate() 中添加一个键,指示手机是否应该开始收集数据 .

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

    在电话中,在 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
            }
        }
    

    然后,您的 Volley 请求的 onResponse 应该将数据传回给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);
    
     }
    

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

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

    你需要 Wearable.API 来实现这个,你的类应该实现 DataApi.DataListener . 有关入门的更多信息,请参阅Accessing the Wearable Data LayerSyncing Data Items

    希望这可以帮助 .

  • 1

    如果你可以排除连接问题,你可以尝试替代排球:

    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'
    

    版本很重要 .

    然后根据您的要求:

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

    然后只需从线程/ asynctask执行您的代码/让它略微延迟您的前端

    编辑:以防万一附加 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());
    }
    

    另外,请注意,请确保将这两种方法的返回类型从void更改为Map

  • 2

    这不仅仅是当 Watch 通过蓝牙连接到手机的情况下,互联网无法正常工作,因为wifi已关闭 . 如果 Watch 使用wifi连接到手机,那么它将工作 .

    我正在研究穿2.0应用程序,只是在我的手机上关闭蓝牙,我的 Watch 可以上网 .

相关问题