android - 如何从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();
}
}
}
}
这是错误的图像
解决方案
这里的问题是您没有考虑到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);
}
}
我希望它有所帮助,并且已经足够清楚了。
干杯!
推荐阅读
- python - Python / pingouin : ValueError: zero_method 'wilcox' 和 'pratt' 如果 x - y 对于所有元素都为零,则不起作用
- c - 当我中断主进程的执行时,子进程会发生什么?
- github - 从 github 导入项目并执行 main 没有错误后,out 文件在 intellij 中标记为红色
- node.js - 如何找出连接到 Express 服务器的客户端的 DNS 名称服务器?
- java - 如何在 JavaExec 任务中正确添加 --add-opens 到 jvmArgs
- c# - “System.Dynamic.ExpandoObject”不包含 Specflow C# 中“用户名”的定义
- python - 如何使用来自用户的多个输入过滤数据框
- javascript - 在板上传递图像
- java - 有没有办法从 Java 类中检查它的超类是否属于同一类型?
- javascript - 用于创建 DOM 元素的 For 循环中的 JSON“具有”方法