我正在开发我的第一个应用程序,我创建了以下方法,该方法连接到远程url,获取JSON文件并将其写入本地SQLite数据库。有时互联网连接很慢或不好,我会设置一个计时器。例如,如果3秒钟后它没有得到JSON文件,我会抛出AlertDialog,让用户选择重试还是取消。那么,如何将超时添加到我的函数中呢?
public int storeData(Database db, int num) throws JSONException {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://www.example.com/file.json");
request.addHeader("Cache-Control", "no-cache");
long id = -1;
try {
HttpResponse response = client.execute(request);
HttpEntity entity = response.getEntity();
InputStreamReader in = new InputStreamReader(entity.getContent());
BufferedReader reader = new BufferedReader(in);
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line=reader.readLine()) != null) {
stringBuilder.append(line);
}
JSONArray jsonArray = new JSONArray(stringBuilder.toString());
SQLiteDatabase dbWrite = db.getWritableDatabase();
ContentValues values = new ContentValues();
if (jsonArray.length() == num && num != 0)
return num;
SQLiteDatabase dbread = db.getReadableDatabase();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jObj = (JSONObject) jsonArray.getJSONObject(i);
values.put("id", jObj.optString("id").toString());
values.put("name", jObj.optString("firstname").toString());
values.put("surname",jObj.optString("lastname").toString());
id = dbWrite.insert("users", null, values);
}
num = jsonArray.length();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (id > 0)
return num;
else
return -1;
}
需要考虑的几件事:
-
套接字和HTTP连接超时
首先,修改您的HTTP连接以使连接和套接字超时
BasicHttpParams basicParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout( basicParams, timeout * 1000 ); HttpConnectionParams.setSoTimeout( basicParams, timeout * 1000 ); DefaultHttpClient client = new DefaultHttpClient( basicParams );
-
在超时时优雅地退出您的挂起请求
-
如果响应数据很大,您可能会在慢速连接上耗尽时间,在这种情况下,我们需要优雅地关闭HTTPClient资源。
-
我假设您已经在一个单独的线程中调用了这个
storeData
,我建议您使用AsyncTask,因为我们可以在超时时调用它的cancel
方法。您的storeData
代码将在asyncTask的doInBackground
中,并且在读取实体响应数据的"while"循环中,您可以检查asyncTask的isCancelled并优雅地关闭if (isCancelled()) { EntityUtils.consume(entity); client.getConnectionManager().shutdown(); return -1; }
-
在asyncTask的postExecute函数中,您可以将
isDone
设置为指示请求成功,而不需要任何超时和任何其他UI处理。protected void onPostExecute(...) { isDone = true; }
-
-
调度和处理主UI线程上的超时
以上两个将处理连接超时、数据超时和慢速连接超时。现在,我们需要处理设置超时并从UI进行管理。为此,我们可以使用@Neutrino建议的简单延迟
handler
runnable
。boolean isDone = false; StoreDataTask storeDataTask = new StoreDataTask(); storeDataTask.execute(...) new Handler().postDelayed(new Runnable() { public void run() { storeDataTask.cancel(false); } }, timeout * 1000); if (isDone) // we have a successful request without timeout
将上面的代码段封装在一个函数中,如果用户想重试,请再次调用它。注意,如果用户不想等待超时,只想取消超时,您可以随时从onCreate或UI线程调用
storeDataTask.cancel(false);
使用这样的处理程序-
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Check if JSON file is there
//This code will be executed after 3 seconds
}
}, 3000); //Change time here. The time is in milliseconds. 1 sec = 1000 ms.
//The code above will be executed after given time.
把这个代码放在最后。