Shopper App [Update], Backgroundtasks, Services, AsyncTasks #7

Hello,

This will be just a short post in order to discuss background tasks on android. In my last post, when i showed you the code which is responsible for creating a new groupname on the shopper server, i said that this is just a little task which should not be much timeconsuming, so that we don’t have to stuck it in a extra service. But today, as i tested the whole thing on my android device it came out that this little task needs his time. For example creating a group (for the first time) needs about 4-5 seconds. In these seconds the UI is blocked and it seems to the user that the whole thing hung. So i will show you now what can be done on the android platform to handle longtime-tasks.

The UI-Thread is the Main-Thread of an android application and is in charge of dispatching events to the appropriate widgets. If everything happens in this single thread your application could suffer from performance issues. Because long operations, such as network operations, database queries, etc, will absolutely block the whole UI.

The first approach to this problem would be, to handle the operations in a new runnable Thread especcially in its run() method. This seems good but unfortinally this is no good solution. It violates the single threaded model of the UI of android because the UI toolkit of android is not threadsafe. So using such workerthreads to handle longtime tasks can cause weird problems and are hard to find and fix.

Fortunately, Android provides good concepts which makes it easy to run backgroundtasks. And one of the most comfortable ways on the android platform is to use the socalled AsyncTask class which is available since Android 1.5. It simplifies the creation of long-running tasks that need to communicate with the user interface. Let’t take a look at the updated AsyncTask which is responsible for communicating with our webservice for creating a new group:

public class NewGroupActivity extends Activity {

	private final String URL_TO_SEND_REQUEST = "http://1.latest.pms-server.appspot.com/rest/groups/new";
	private final String TARGET_DOMAIN = "1.latest.pms-server.appspot.com";
	private boolean SUCCESS = false;

	private Button mOkBtn;
	private Button mCancelBtn;
	private EditText mGroupnameTxt;
	private ProgressBar mProgressBar;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.new_group);

		mOkBtn = (Button) findViewById(R.id.ok);
		mCancelBtn = (Button) findViewById(R.id.cancel);
		mGroupnameTxt = (EditText) findViewById(R.id.groupname);
		mProgressBar = (ProgressBar) findViewById(R.id.progressbar);
		mProgressBar.setVisibility(ProgressBar.INVISIBLE);

		mOkBtn.setOnClickListener(new View.OnClickListener() {

			public void onClick(View view) {

				mProgressBar.setVisibility(ProgressBar.VISIBLE);
				String contentToSend = mGroupnameTxt.getText().toString()
						.trim();

				// start the async task
				new NewGroupCallTask().execute(contentToSend);

			}
		});

		mCancelBtn.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				finish();
			}
		});
	}

	// Backgroundtask
	private class NewGroupCallTask extends AsyncTask<String, Integer, String> {

		@Override
		protected String doInBackground(String... arg0) {

			String contentToSend = arg0[0];
			DefaultHttpClient httpClient = new DefaultHttpClient();
			HttpHost targetHost = new HttpHost(TARGET_DOMAIN, 80, "http");
			HttpPost httpPost = new HttpPost(URL_TO_SEND_REQUEST);

			String result = "";
			try {
				StringEntity entity = new StringEntity(contentToSend, "UTF-8");
				entity.setContentType("text/plain");
				httpPost.setEntity(entity);

				HttpResponse response = httpClient
						.execute(targetHost, httpPost);

				HttpEntity httpentity = response.getEntity();

				InputStream instream = httpentity.getContent();
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(instream));
				StringBuilder sb = new StringBuilder();

				String line = null;

				while ((line = reader.readLine()) != null) {
					sb.append(line + "\n");
				}

				result = sb.toString();

				SUCCESS = response.getStatusLine().getStatusCode() != 500 ? true
						: false;

			} catch (Exception ex) {
				ex.printStackTrace();
				result += ex.getMessage();
			}
			return result;
		}

		@Override
		protected void onPostExecute(String result) {
			mProgressBar.setVisibility(ProgressBar.INVISIBLE);
			Toast.makeText(NewGroupActivity.this, result, Toast.LENGTH_LONG)
					.show();

			super.onPostExecute(result);
			if (SUCCESS) {
				finish();
			}
		}

	}

}

Every AsyncTask have to extend the AsyncTask class with some generic types to define which type this Task is able to consume and which one it will produce. Our Task will consume just Strings and return a String again (the String which comes from the server). If the Task is finished (if the Restcall is finished) the onPostExecute() method is invoked on the UI thread with the resultstring of the Task. The whole task can be started with the execute() method. new NewGroupCallTask().execute(contentToSend);

To inform the user about the progress, a animated circlelike progressbar is shown at the UserInterface. (see picture)

So, now the whole UI is not blocking anymore (yaaay :) ) and the user gets a perfect feedback, via the rotating progressbar if the network call is finished or in progress yet. Fantastic isn’t it? :P

, , , , ,
  • Delicious
  • Facebook
  • Digg
  • Reddit
  • StumbleUpon
  • Twitter

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>