ANDROID: TP1
APPING-MASTERS-2013-VERDIER
Android: Session Two
Part 1: DelayedWork
The goal of this exercise is to use a thread to do some work in background, so that the UI is still
responsive.
Well be making an application that do the following tasks in background
Sleep and then display a message
Download an image and display it
First step: Create the UI
Create
a
DelayedWork
android
project,
in
SDK
2.3.3
The interface needs to have its default TextView at the top, 2 buttons and an ImageView. Here is a
screenshot of it:
PAGE 1 OF 7
ANDROID: TP1
APPING-MASTERS-2013-VERDIER
Create
the
user
interface.
Change the root layout to Linear Layout.
For the ImageView, set the following fields:
layout_width and layout_height to 100dp
src to @drawable/ic_launcher (a resource that is part of the default Android project)
The Hierarchy Viewer
There is a very useful tool called Hierarchy Viewer that let you see how the UI of a running activity is
structured.
This tool is part of the SDK so it can be found in the SDK/Tools directory, but recently Google included
it in the ADT plugin. As such, its now accessible directly in Eclipse [Windows->Open perspective>Other->Hierarchy View].
Launch
the
hierarchy
viewer
Your application has to be running for the tool to see it. If you dont see your application, refresh the list of
currently running activities in the Windows tab.
To give you a better understanding of how our application UI is structured, here is its hierarchy view.
As you can see we have multiple nested linearLayouts:
The first one is a horizontal LinearLayout that contains the ImageView and a LinearLayout
The second one is a vertical LinearLayout with the 2 buttons
PAGE 2 OF 7
ANDROID: TP1
APPING-MASTERS-2013-VERDIER
Second step: DelayedMessage
The UI thread is the only one allowed to modify the UI. In android, the easiest way to do work in
background and still be able to access the UI is to use the AsyncTask class because it will do the thread
work for you.
Inside
your
MainActivity
class,
create
a
new
subclass
of
AsyncTask
called
DelayedMessage.
You will need to implement: the following methods:
doInBackground(): called when the AsyncTask is executed; its the actual work you want to do in
background
onPostExecute(): called when the AsyncTask finishes; its the place where you are allowed to
access your UI
An AsyncTask<Params, Progress, Result> class is defined by 3 generics types:
Params: the type of the parameters sent to the task upon execution
Progress: the type of the progress units published during the background computation
Result: the type of the result of the background computation.
As an example here is a code that logs the string given as parameter to the AsyncTask:
class DelayedMessage extends AsyncTask<String, Integer, String>
{
@Override
protected String doInBackground(String... params)
{
//your code here
return params[0];
}
@Override
protected void onPostExecute(String result)
{
//your code here
Log.d(TAG, result);
}
And here is how you call it in your code:
DelayedMessage foobar = new DelayedMessage();
foobar.execute("hello world");
PAGE 3 OF 7
ANDROID: TP1
APPING-MASTERS-2013-VERDIER
Use
the
doInBackground()
method
to
sleep
1000
ms
and
then
display
a
toast
notication
in
the
onPostExecute()
method.
Use your DelayedMessage class to display the message when the DelayedMessage button is clicked.
Third step: BackgroundImageDl
Now we want to be able to download an image when the DelayedSmiley button is pressed without
blocking the UI.
First
of
all,
you
have
to
add
a
uses-permission
to
be
allowed
to
use
internet
in
your
application.
On the device, the user has to grant permissions to each application when its installed. On the emulator,
the application already has those rights, so no question is asked.
Add the following in your AndroidManifest.xml file, before the closing tag:
<uses-permission android:name="android.permission.INTERNET" />
Create
a
new
BackgroundImageDl
class
inside
your
activity
the
same
way
your
created
your
previous
DelayedMessage
class.
Here some code to download an image from a URL string and generate a Drawable object that you can
display in your ImageView:
URL url = new URL(stringUrl);
//extra sleep to simulate a longer download
Thread.sleep(1000);
Object content = url.getContent();
InputStream is = (InputStream) content;
Drawable d = Drawable.createFromStream(is, "src");
Your doInBackground() method has to download the image from the URL string that is passed to the
AsyncTask.Execute() method, generate a Drawable object and then return it so that the
onPostExecute() method can display it.
Download
and
display
the
following
image
when
the
user
clicks
on
the
DelayedSmiley
url: http://education.3ie.fr/android/smiley.png
Fourth step: Refactoring
PAGE 4 OF 7
ANDROID: TP1
APPING-MASTERS-2013-VERDIER
The way we added the BackgroundImageDl class in our main Java file is eective but kind of ugly. A
better way to do it is to use a separate class for your AsyncTask.
Since we are outside of our Activity, we dont have the reference to the imageView so we have to give it to
this class we are creating.
Here is what your class is going to look like. You have to fill the blanks and then use this ImageDownload
class instead of our previous DelayedMessage.
public class ImageDownloader
{
public void download(String url, ImageView imageView)
{
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
task.execute(url);
}
class BitmapDownloaderTask extends AsyncTask<String, Integer, Drawable>
{
private final ImageView imageViewReference;
public BitmapDownloaderTask(ImageView imageView) {
//TODO: save the reference to the imageView
}
@Override
// Actual download method, run in the task thread
protected Drawable doInBackground(String... params) {
//TODO
}
@Override
protected void onProgressUpdate(Integer... values) {
//nothing to do here
}
@Override
protected void onPostExecute(Drawable d) {
//TODO
}
PAGE 5 OF 7
ANDROID: TP1
APPING-MASTERS-2013-VERDIER
Part 2: RelativeLayout
First step: RelativeLayout presentation
This
step
is
not
an
exercise,
just
some
explanations.
The RelativeLayout works in such a way that the programmer describes how the various widgets are
related to one another. It is very powerful but not as easy to understand as the LinearLayout.
The best way to explain it is to look at a simple example.
We want to make this simple UI that cannot be done with only one LinearLayout:
To make this kind of interface with only LinearLayouts, we would have to create multiple nested
LinearLayouts because of the 2 buttons we want to have next to each other.
Here is how you could structure your layout (not the complete XML):
<LinearLayout android:orientation="vertical" >
<EditText />
<LinearLayout android:orientation="horizontal" >
<Button />
<Button />
</LinearLayout>
</LinearLayout>
In RelativeLayout, we can easily place the 2 buttons next 2 each other without having to use another
nested Layout, so the UI is faster to render.
Here is how you could structure the previous UI in relative layout (not the complete XML):
PAGE 6 OF 7
ANDROID: TP1
APPING-MASTERS-2013-VERDIER
<RelativeLayout >
<EditText
android:id="@+id/editText1"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
<Button
android:id="@+id/button1"
android:layout_alignParentLeft="true"
android:layout_below="@+id/editText1" />
<Button
android:id="@+id/button2"
android:layout_below="@+id/editText1"
android:layout_toRightOf="@+id/button1" />
</RelativeLayout>
Notice how the button2 is configured to be below the editText and to the right of the button1.
Second step: DelayedMessage UI
You are going the redo the UI for the previous exercise . The interface hierarchy in relative layout will be
much more simple than the previously nested LinearLayout. You only need a root RelativeLayout to host
all the others widgets.
Modify
your
UI
to
make
it
use
a
relative
layout.
The screenshot shows you the way you UI should be structured.
PAGE 7 OF 7