首页 > 解决方案 > 如何从android的json中的url获取响应,而不是在响应之后我想解析它

问题描述

我正在尝试从 thingspeak api 获取数据,我正在输入通道 ID 并将其传递到 URL。但是我必须检查 url 是否响应,如果它响应而不是继续使用代码,否则用户必须更改频道 ID。

我得到的错误是 空对象引用上的“int java.lang.String.length()”

W/System.err:java.io.FileNotFoundException:https ://api.thingspeak.com/channels/497971/feeds.json?results=1

如果我将其更改为,这是无效的 url

https://api.thingspeak.com/channels/497970/feeds.json?results=1

这将起作用

我正在尝试的代码是

    public class MainActivity extends AppCompatActivity {
    TextView a, b;
    String result = "";
    String field1,field2,field3;
    private int count = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        a = (TextView) findViewById(R.id.a);
        b = (TextView) findViewById(R.id.b);

        new CountDownTimer(100000, 10000) {
            @Override
            public void onTick(long l) {
                DownloadTask task = new DownloadTask();
                task.execute("https://api.thingspeak.com/channels/497970/feeds.json?results=1");
            }

            @Override
            public void onFinish() {

            }
        }.start();
    }

    public class DownloadTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... urls) {
            URL url;
            result = "";
            HttpURLConnection urlConnection = null;
            try {
                url = new URL(urls[0]);
                urlConnection = (HttpURLConnection) url.openConnection();
                InputStream in = urlConnection.getInputStream();
                InputStreamReader reader = new InputStreamReader(in);
                int data = reader.read();
                while (data != -1) {
                    char current = (char) data;
                    result += current;
                    data = reader.read();
                }
                return result;
            } catch (MalformedURLException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            return null;
        }


        @Override
        protected void onPostExecute(final String result) {
            super.onPostExecute(result);

            search(result);
        }

        public void search(String result) {
            try {
                JSONObject jsonObject = new JSONObject(result);
                JSONObject fieldinfo = jsonObject.getJSONObject("channel");

                String ff1 =  fieldinfo.optString("field1","No Value");
                String ff2 = fieldinfo.optString("field2","No Value");

                JSONArray weatherInfo = jsonObject.getJSONArray("feeds");

                JSONObject legsobject = weatherInfo.getJSONObject(0);
                  field1 = legsobject.getString("field1");
                  field2 = legsobject.getString("field2");

                a.setText(ff1);

                c.setText(field1);

            } catch (JSONException e1) {
                e1.printStackTrace();
            }

        }
    }
}

这是错误的图像

**这是错误的图像**

标签: androidexception

解决方案


这里的问题是您没有考虑到HTTP 连接有时确实会失败,就像在这种情况下一样。它失败了,因为通道 id 不存在。

当您设置正确的频道 ID 时,该 URL 也是正确的,因为该资源存在,因此您可以获得所需的结果。

但是,当您设置错误的通道 ID 时,HTTP 请求会失败(因为该 URL 不存在)。不管怎样,您都在尝试阅读响应,而这一切都爆发了

当您向服务器发出 HTTP 请求时,它会以状态代码进行响应,指示您的请求发生了什么。您完全忽略了此状态代码。

使用以下命令查看对该 URL 的请求所引发的标头:

curl -i https://api.thingspeak.com/channels/497971/feeds.json?results=1

HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: close
Status: 400 Bad Request
... [Shortened] ...

您可以在简单的 Google 搜索中了解有关 HTTP 状态代码的所有信息,但总结是它是一个介于 100 和 599 之间的数字,表示:

  • 请求成功处理:当它在 200 和 299 之间时。
  • 请求无法处理,失败:在 400 到 499 之间。
  • 请求失败,因为服务器基本上炸了:(> 500)。

为了检索此状态码,您需要调用实例的getResponseCode()方法。urlConnection

只有当状态码成功(200 到 299 之间)时,调用urlConnection.getInputStream()才会成功。如果出现错误,您需要调用urlConnection.getErrorStream().

因此,为了修复您的代码,您需要执行以下操作:

@Override
protected String doInBackground(String... urls) {
    URL url;
    result = "";
    HttpURLConnection urlConnection = null;
    try {
        url = new URL(urls[0]);
        // Open the conection
        urlConnection = (HttpURLConnection) url.openConnection();
        // Retrieve status code
        int statusCode = urlConnection.getResponseCode();
        // Determine whether the request was handled successfully or not
        boolean success = (statusCode >= 200) && (statusCode < 300);
        InputStream in;
        if(success) {
            // Read the response when request was handled successfully
            in = urlConnection.getInputStream();
        } else {
            // Read the error stream when the request failed
            in = urlConnection.getErrorStream();
        }
        InputStreamReader reader = new InputStreamReader(in);
        int data = reader.read();
        while (data != -1) {
            char current = (char) data;
            result += current;
            data = reader.read();
        }
        return result;
    } catch (MalformedURLException e1) {
        e1.printStackTrace();
    } catch (IOException e1) {
        e1.printStackTrace();
    } finally {
        // Close the connection
        if(urlConnection != null) {
            urlConnection.disconnect();
        }
    }
    return null;
}

首先,完成后不要忘记关闭连接(我在finally {}块中包含了断开连接)。

如果您调试或记录该代码,您将看到您收到的状态代码是 400。这是 的 HTTP 状态代码Bad Request,表明您的请求不正确,您需要修复它。如果分析result变量的内容,您将看到该值等于-1。

因此,在onPostExecute回调中,您应该在尝试反序列化之前确保该值不同于 -1,否则它将再次爆炸。

您可以像这样修复onPostExecute回调

@Override
    protected void onPostExecute(final String result) {
        super.onPostExecute(result);
        if(result.equals(-1)) {
            // Do something else, show an error to the user indicating the channel id is wrong
        } else {
            // Since there is no error, you can proceed with the deserialization of the response
            search(result);
        }
    }

我希望它有所帮助,并且已经足够清楚了。

干杯!


推荐阅读