我有一个Android IntentService连接到Web服务,以json格式下载一些作业。然后将它们解析并放入SQLite3 DB中。
以下代码(添加了敏感位)在仿真器上运行但从未在实际设备上运行。
public class FetchJobsService extends IntentService {
private final static String LOG_TAG = "FetchJobsService";
public FetchJobsService() {
super("FetchJobsService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i(LOG_TAG, "Fetch Jobs Service Started");
AsyncHttpClient client = new AsyncHttpClient();
Map<String, Object> params = new HashMap<String, Object>();
// Add params to send in the request!
JSONObject jsonData = new JSONObject(params);
RequestParams requestParams = new RequestParams();
requestParams.put(Constants.DATA, jsonData.toString());
client.post(Constants.FETCH_JOBS, requestParams,
new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int i, Header[] headers, byte[] bytes) {
try {
JSONObject returnObj = new JSONObject(new String(bytes));
Log.i(LOG_TAG, "Success! Jobs downloaded");
JSONObject dataObj = returnObj.getJSONObject(Constants.DATA);
JSONArray jobs = dataObj.getJSONArray(Constants.JOBS);
// Do something with the data downloaded!
} catch (JSONException e) {
Log.e(LOG_TAG, "Failure! Jobs not successfully downloaded", e);
}
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] bytes,
Throwable throwable) {
Log.i(LOG_TAG, "Failure! Status Code: " + statusCode);
}
}
);
Log.i(LOG_TAG, "Fetch Jobs Service Finished");
}
}
它抱怨发布到死线程。经过一些阅读后,我添加了一个Looper来保持IntentService,直到数据被下载和解析为止:
public class FetchJobsService extends IntentService {
private final static String LOG_TAG = "FetchJobsService";
public FetchJobsService() {
super("FetchJobsService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i(LOG_TAG, "Fetch Jobs Service Started");
if (Looper.myLooper() == null) {
Looper.prepare();
}
AsyncHttpClient client = new AsyncHttpClient();
Map<String, Object> params = new HashMap<String, Object>();
// Add params to send in the request!
JSONObject jsonData = new JSONObject(params);
RequestParams requestParams = new RequestParams();
requestParams.put(Constants.DATA, jsonData.toString());
client.post(Constants.FETCH_JOBS, requestParams,
new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int i, Header[] headers, byte[] bytes) {
try {
JSONObject returnObj = new JSONObject(new String(bytes));
Log.i(LOG_TAG, "Success! Jobs downloaded");
JSONObject dataObj = returnObj.getJSONObject(Constants.DATA);
JSONArray jobs = dataObj.getJSONArray(Constants.JOBS);
// Do something with the data downloaded!
} catch (JSONException e) {
Log.e(LOG_TAG, "Failure! Jobs not successfully downloaded", e);
} finally {
if (Looper.myLooper() != null) {
Looper.myLooper().quit();
}
}
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] bytes,
Throwable throwable) {
Log.i(LOG_TAG, "Failure! Status Code: " + statusCode);
if (Looper.myLooper() != null) {
Looper.myLooper().quit();
}
}
}
);
Looper.loop();
Log.i(LOG_TAG, "Fetch Jobs Service Finished");
}
}
现在已成功下载作业,但是对quit()
或quitSafely()
的调用导致崩溃Fatal signal 11 (SIGSEGV) at 0x0000000c (code=1)
。
如果我删除了对quit()的调用,那么没有崩溃,但显然服务不会停止并释放资源,直到应用程序退出。
我做错了什么?
答案 0 :(得分:1)
IntentService旨在处理自己的生命周期。您只需覆盖onHandleIntent
回调并执行您需要执行的操作 - 一旦此方法退出,IntentService将自行关闭。
IntentService已经在一个单独的线程中运行,因此异步发出请求是没有意义的。您应该在onHandleIntent
回调中同步执行网络呼叫。 this article中有一些例子。
你可以尝试这些方法:
HttpEntity requestEntity = new UrlEncodedFormEntity(params);
//set up post request
final HttpPost post = new HttpPost(url);
post.addHeader(requestEntity.getContentType());
post.setEntity(requestEntity);
//get http client
DefaultHttpClient mHttpClient = new DefaultHttpClient();
final HttpParams httpParams = mHttpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT);
HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT);
ConnManagerParams.setTimeout(httpParams, TIMEOUT);
// get response -- this line will block until it is complete -- which is completely fine in an IntentService!
HttpResponse response = getHttpClient().execute(post);
int statusCode = response.getStatusLine().getStatusCode();
String responseEntity = EntityUtils.toString(response.getEntity());
if (statusCode != HttpStatus.SC_OK) {
// something bad happened, request failed!
} else{
// response was good, and "responseEntity" can be used for whatever you need
}