In my journey learning android, i came across the need to finally spin a thread. I am calling out to an api, and need to send some post data, as well as of course, get a response. i read all sorts of ways to handle this from running a thread/runnable to the seemingly preferred AsyncTask.
I’m opting for the later, but wanted to jot some things about how this works, given i am not a Java developer and the syntax of the AsyncTask threw me for a loop.
Setup
The basics work like this:
- extend the AsyncTask class
- override doInBackground, onProgressUpdate, onPostExecute methods in your AsyncTask…there is also a onCancelled, and few others
- create a new instance of your AsyncTask class
- fire off your new thread: yourClassInstance.execute();
- if you need to, you can cancel the thread’s task: yourClassInstance.cancel();
My project has a feature that necessitates the application call home a la an api for the latest published version of the app. For this to work, our api expects two variables: “platform” (“Android” or “iOS”), and a boolean tablet identification (“isTablet”) to differentiate the phone vs tablet os publications. The server will respond a simple xml feed that states the most current os for that platform and some other useless things for this example.
Syntax
AsyncTask has this interesting syntax with the “
- the variable we are sending into doInBackground
- the variable we use for onProgressUpdate
- the variable returned to onPostExecute , which is when we return to the main thread
Making it happen…
My application fires up…normally i have a class that’s sole job is to make the versioning query, and compare the apps version string to that of the result, then fire the appropriate event for what it discovered. However for brevity, here’s the gist from the launch activity.Here’s how it all comes together for my needs:
public class MyAppKeypadActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.launch_activity); _checkVersion(); // ...some other things } private void _checkVersion() { MyAppVersionObject ob = null; PackageInfo info = null; PackageManager pm = _ctx.getPackageManager(); String packageName = _ctx.getPackageName(); try { info = pm.getPackageInfo(packageName,0); } catch (NameNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (info != null) { try { _currentLocalVersion = info.versionName; Intent i = new Intent(_ctx,MyAppAPIService.class); i.putExtra(MyAppAPIService.INTENTTYPE, MyAppAPIService.INTENT_VERSION); _ctx.startService(i); } catch (Exception e) { //TODO: deal with this exception } } } }
in MyAppAPIService class, it goes something like:
public class MyAppAPIService extends Service implements MyAppXMLEventListener{ @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); Context context = getApplicationContext(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); Bundle b = intent.getExtras(); String _tpe = b.getString(MyAppAPIService.INTENTTYPE); //..comparing intents if (_tpe.equals(MyAppAPIService.INTENT_VERSION)) { doVersioning(); } } private void doVersioning() { VersioningHandler versionhandler = new VersioningHandler(); versionhandler.execute((Void)null); } private class VersioningHandler extends AsyncTask<Void, Integer, Boolean> { private boolean _isSuccess = true; @Override protected Boolean doInBackground(Void... params) { String response = null; HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost(getBaseUrl() + "version"); try { //POST vars to send List<NameValuePair> namevaluePairs = new ArrayList<NameValuePair>(); namevaluePairs.add(new BasicNameValuePair(MyAppAPIService.EXTRA_ISTABLET,"0")); namevaluePairs.add(new BasicNameValuePair(MyAppAPIService.EXTRA_PLATFORM,"Android" )); post.setEntity(new UrlEncodedFormEntity(namevaluePairs)); Log.d("api",getBaseUrl() + "version"); // Execute HTTP Post Request ResponseHandler<String> responseHandler=new BasicResponseHandler(); response = client.execute(post, responseHandler); } catch (ClientProtocolException e) { _isSuccess = false; } catch (IOException e) { _isSuccess = false; } catch (Exception e) { _isSuccess = false; } if (response != null) { parseVersionResponseXML(response);//parse the xml response }else { String st = getApplication().getString(R.string.apiErrorSignin).toString(); Intent i = new Intent(MyAppAPIService.API_ERROR); i.putExtra(EXTRA_MESSAGE, st); i.putExtra(EXTRA_ERRORCODE, 0); sendBroadcast(i); } return _isSuccess; } @Override protected void onPostExecute(Boolean result) {//result = _isSuccess, returned value of doInBackground if (! result) { } } } }
Obviously i pulled some things out , like all the xml parsing, etc. The real meat here is we have an AsyncTask handling all the background work to get the xml, and deal with it. More so, hopefully, an understanding of how AsyncTask makes threading easy…and how we can intercept some of the workings in that thread.
Hope that helps…