I am having difficulties understanding AsyncTask, even after reading everything about it on Developer.Android. I am looking for some insight in how I should proceed. This is the situation :
I have an Activity which, on an onClick event calls the LoginCheck() method of an underlying LoginController class. The LoginController class then proceeds to fetch whatever information is nescesarry from a UserInfo class or from the Activity(User and Password) and creates an instance of a RestClient which then makes the call to the web service and attempts to log in. RestClient has a private class CallServiceTask that extends AsyncTask.
I have a few design problems here that I hope you can be of assistance with.
- Am I doing it right? Is this a proper way to make sure that any calls to the web service are being done asynchronously?
- How do use onProgressUpdate or whatever to notify the user that the application is in the process of logging in?
- How would I go about getting the data that is saved in DoinBackground() ?
Below you’ll find snippets of the project in question :
RestClient
// From the constructor...
rtnData = new Object[]{ new JSONObject() , Boolean.TRUE };
public void ExecuteCall(RequestMethod method) throws Exception
{
Object[] parameters = new Object[]{ new HttpGet() , new String("") };
switch(method) {
case GET:
{
//add parameters
String combinedParams = "";
if(!params.isEmpty()){
combinedParams += "?";
for(NameValuePair p : params)
{
String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue());
if(combinedParams.length() > 1)
{
combinedParams += "&" + paramString;
}
else
{
combinedParams += paramString;
}
}
}
HttpGet request = new HttpGet(url + combinedParams);
//add headers
for(NameValuePair h : headers)
{
request.addHeader(h.getName(), h.getValue());
}
parameters[0] = request;
parameters[1] = url;
new CallServiceTask().execute(request, url);
jsonData = ((JSONObject) rtnData[0]).optJSONObject("data");
connError = (Boolean) rtnData[1];
break;
}
case POST: ....
}
}
private Object[] executeRequest(HttpUriRequest request, String url)
{
HttpClient client = new DefaultHttpClient();
client = getNewHttpClient();
HttpResponse httpResponse;
try {
httpResponse = client.execute(request);
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String response = convertStreamToString(instream);
try {
rtnData[0] = new JSONObject(response);
rtnData[1] = false;
} catch (JSONException e1) {
rtnData[1] = true;
e1.printStackTrace();
}
// Closing the input stream will trigger connection release
instream.close();
}
} catch (ClientProtocolException e) {
client.getConnectionManager().shutdown();
e.printStackTrace();
} catch (IOException e) {
client.getConnectionManager().shutdown();
e.printStackTrace();
}
return rtnData;
}
CallServiceTask
private class CallServiceTask extends AsyncTask<Object, Void, Object[]>
{
protected Object[] doInBackground(Object... params)
{
HttpUriRequest req = (HttpUriRequest) params[0];
String url = (String) params[1];
return executeRequest(req, url);
}
@Override
protected void onPostExecute(Object[] result)
{
rtnData = result;
}
}
It’s absolutely right that any possibly long running operations should be executed in separate threads. And the
AsyncTaskis a good way to solve this kind of problems, since it also gives you an easy way to synchronize your task with the UI thread. This is the answer to your first question.Now, concerning the UI thread updating to show your users that your application is not stuck. Since an
AsyncTask‘sonPreExecute()andonPostExecute()methods are running inside the UI thread, you can easily create, run and stopProgressDialogs orProgressBars there. If you want to show the current progress of the task, you should callpublishProgress(int)method inside thedoInBackground(), and then make use of it inside theAsyncTask‘sonProgressUpdate()method. There you can, for example, update yourProgressDialog.And to get the result out of your AsyncTask you can either call its
get()method (this a synchronous call), or implement some kind of callback interface that will tell the activity that the task has finished.I hope the answer is clear enough, if no – feel free to ask more questions. Hope this helps.
EDIT
Create an interface called, for example,
onFetchFinishedListenerwith one method –void onFetchFinished(String). Your activity, that starts theAsyncTask, must implement this interface. Now create a constructor inside yourAsyncTaskthat takes anOnFetchFinishedListenerobject as an argument, and when instantiating theAsyncTaskinside your activity send a reference to theActivityas the argument (since it implementsOnFetchFinishedListener). Then when your task is finished insidedoInBackground()callonFetchFinished()on the activity. Now inside theonFetchFinished(String)method of yourActivityyou can make use of theString(or another object) that’s brought with the callback. Again, hope I was clear enough.