You are on page 1of 55

Mobile applications

Concurrency, Notifications and Alarms

Óscar David Sánchez

University of Valencia

Topic 4, Concurrency, Notification, Alarms 1/55


Outline

1 Concurrent programming

2 Notifications

3 Alarms

Topic 4, Concurrency, Notification, Alarms 2/55


Concurrent programming

Índice

1 Concurrent programming

2 Notifications

3 Alarms

Topic 4, Concurrency, Notification, Alarms 3/55


Concurrent programming Introduction

Índice

1 Concurrent programming
Introduction
AsyncTask
Handler

Topic 4, Concurrency, Notification, Alarms 4/55


Concurrent programming Introduction

Introduction

Threads allow running tasks concurrently.


The concurrency will be real if the device has several CPUs and each
thread runs on a CPU.
Threads that run in a process have access to dynamic memory and static
variables (for instance, they can share an object).
Therefore, it is easier to share information between the threads running in a
process than between different processes.

Topic 4, Concurrency, Notification, Alarms 5/55


Concurrent programming Introduction

Thread class

The Thread class allows to execute code concurrently.


This class has, among others, the methods:
// Method that you have to write in the subclass
// It is the method where the code can be defined
// run concurrently
public void run(){}

// Is the method that executes the code of the run method


// concurrently
public void start(){...}

// Stop thread execution for the indicated time (in milliseconds)


public void sleep(long tiempo) throws InterruptedException{...}

// Stop the thread where this call has been made until the end
// the execution
public void join(){...}

Topic 4, Concurrency, Notification, Alarms 6/55


Concurrent programming Introduction

Use of Thread

Declaration of a class that extends Thread


class Hilo extends Thread{
public void run(){
// Code that can be run concurrently
}
}

Creation of instances and concurrent execution:


Hilo h1 = new Hilo();
Hilo h2 = new Hilo();
h1.start();
h2.start();

The call to the start() method causes the code of the run() method to
run concurrently

Topic 4, Concurrency, Notification, Alarms 7/55


Concurrent programming Introduction

Problems with shared resources: need for mutual exclusion

Suppose that an instance of the following class is going to be shared by two


threads:
class Counter{
private double value = 0;

// Method to increase the value of the counter


public void increase() {
value++;
}

// Method to decrease the value of the counter


public void decrease(){
value--;
}

// Method to check the value of the counter


public double getValue(){
return value;
}
}

Topic 4, Concurrency, Notification, Alarms 8/55


Concurrent programming Introduction

Example of concurrent tasks using the resource


class IncrementThread extends Thread{
private Counter c;

IncrementThread(Counter c) {
this.c = c;
}
public void run(){
for (int i=0;i<2000;i++)
c.increase();
}
}

class DecrementThread extends Thread{


private Counter c;

DecrementThread(Counter c) {
this.c = c;
}
public void run(){
for (int i=0;i<2000;i++)
c.decrease();
}
}

Topic 4, Concurrency, Notification, Alarms 9/55


Concurrent programming Introduction

Creation of the shared resource and concurrent tasks


class Test {
public static void main(String[ ] args){
Counter c = new Counter();
// That instance is shared in the two threads
IncrementThread inc = new IncrementThread(c);
DecrementThread dec = new DecrementThread(c);
// Run code concurrently
inc.start();
dec.start();
try{
inc.join();
dec.join();
}catch(InterruptedException ex){}
// Obtain the value of the counter when the two threads are finished
System.out.println(c.getValue());
}
}

One thread increases 2000 times and the other decreases 2000 times, the
result should be zero.
Values for different executions: -369, 286, -624, -434, -1256, 35, . . .
Topic 4, Concurrency, Notification, Alarms 10/55
Concurrent programming Introduction

Solution: mutual exclusion

When all we want is for the methods to be executed as if they were atomic
operations.
Posibilities: use Semaphore, use synchronized blocks, or declare the
methods as synchronized:
class Counter{
private double value = 0;
// Method to increase the value of the counter
public synchronized void increase() {
value++;
}
// Method to decrease the value of the counter
public synchronized void decrease(){
value--;
}
// Method to check the value of the counter
public synchronized double getValue(){
return value;
}
}

Topic 4, Concurrency, Notification, Alarms 11/55


Concurrent programming Introduction

Synchronization for cooperation

In other cases, in addition to mutual exclusion, it is necessary to coordinate


the tasks: if a task can not continue it must wait so other task can get the
lock.
If that other task has performed an action that has modified the attributes,
then it is possible that a task that was waiting can continue.
Methods, offered in Object, related to the synchronization of concurrent
tasks (monitor):
// If the task cannot continue it must wait. The task frees the lock.
public void wait() throws InterruptedException{...}

// Wake up one of the tasks that is waiting


public void notify(){...}

// Wake up all the tasks that are waiting


public void notifyAll(){...}

Topic 4, Concurrency, Notification, Alarms 12/55


Concurrent programming Introduction

When to use threads?

Listener that takes too much to finish


All the listener methods are called sequentially from a single thread.
If a listener method takes much time to complete, then other events that
occur in the user interface (UI) can not be processed.
In these cases it is necessary to move that code to another thread.

Network connections
Network connections (UDP, TCP, HTTP) must be performed in separate
threads because they have blocking operations.

Topic 4, Concurrency, Notification, Alarms 13/55


Concurrent programming Introduction

UI thread

The user interface is created from a thread called main thread (or UI
thread).
From the code of a different thread we can not modify the UI. If we do
that the application finishes with an error.
Android offers different mechanisms to send code to the UI thread from
another thread.
// Method of the View class
public void post(Runnable accion)

// Method of the Activity class


public void runOnUiThread(Runnable accion)

In both cases, the code inside the run() method of the Runnable
argument is executed in the UI thread.

Topic 4, Concurrency, Notification, Alarms 14/55


Concurrent programming AsyncTask

Índice

1 Concurrent programming
Introduction
AsyncTask
Handler

Topic 4, Concurrency, Notification, Alarms 15/55


Concurrent programming AsyncTask

AsyncTask

AsyncTask simplifies the creation of tasks that must be executed in a


separate thread, that will last a few seconds and that must interact with
the graphical interface (for example, updating some View).
This class is parameterized:
AsyncTask<Params, Progress, Result>

The first parameter specifies the type of arguments to be passed when


the task is executed (it can be Void)
The second parameter specifies the type of value that will be used to
report the progress of the task (or Void if not applicable).
The last one indicates the type of the result after executing the task
(o Void if there is no result).

Topic 4, Concurrency, Notification, Alarms 16/55


Concurrent programming AsyncTask

AsyncTask

https://developer.android.com/reference/android/os/AsyncTask.html

This class defines the methods:


Result doInBackground (Params... p)

The code in that method will be executed in a separate thread, so in this


method you can not modify the UI.
The other methods onPreExecute(), onPostExecute(Result r) y
onProgressUpdate(Progress... p) are called from the UI thread
(therefore the views can be accessed and modified in their code).
In addition you can stop the task at any time from any thread.

Topic 4, Concurrency, Notification, Alarms 17/55


Concurrent programming AsyncTask

AsyncTask

To inform the user of the progress made by the background task you can
periodically call publishProgress(Progress p) from the
doInBackground(Params... p) method.
That call runs the code provided in onProgressUpdate(Progress... p)
in the UI thread.
In the code of onProgressUpdate(Progress... p) the user can be
informed of the progress of the task (updating for example a TextView or
a ProgressBar).

Topic 4, Concurrency, Notification, Alarms 18/55


Concurrent programming AsyncTask

Use of AsyncTask
A scheme of use of this class would be the following:
class Actividad extends Activity{
// Attributes of the class

class BackgroundTask extends AsyncTask<Params,Progress,Result>{

public void onPreExecute(){


// It is called automatically before executing the task
}

public Result doInBackgroud(Params... p){


// Carrying out the task
// At any time we can use publishProgress(Progress)
// that runs onProgressUpdate(Progress) in the UI thread
}
public void onProgressUpdate(Progress... p){
// From this method you can update UI elements
//to inform the user of the progress of the action
}
public void onPostExecute(Result r){
// It is called automatically when the doInBackGround () method finishes
// The result of running the task is passed as an argument
}
}
}

Topic 4, Concurrency, Notification, Alarms 19/55


Concurrent programming AsyncTask

AsyncTask

To execute the task:

1 Create, in the UI thread, an instance of the class that extends a


AsyncTask
2 Send the message execute(Params... p), which runs the code in
doInBackground(Params ... p) in a background thread.

Once the task has been executed, it can not be executed again. It is
necessary to recreate another instance (this also happens with Thread).

Topic 4, Concurrency, Notification, Alarms 20/55


Concurrent programming AsyncTask

Java VarArgs

In the argument of some of these methods, three dots appear after the type.
This indicates that they can receive a variable number of arguments of this
type or also an array of that type. Example:
class Example {
public static void metodo(String...p){
int nDatos = p.length;
for (int i=0;i<nDatos; i++)
System.out.print(p[i] + " ");
}
}

class SampleVarArgs{
public static void main(String[] args){
// All these calls are valid
Example.method("String1");
Example.method("String1", "String2");
Example.method("String1", "String2", "String3");
Example.method(new String [] {"String1", "String2", "String3", "String4"});
}
}

Topic 4, Concurrency, Notification, Alarms 21/55


Concurrent programming Handler

Índice

1 Concurrent programming
Introduction
AsyncTask
Handler

Topic 4, Concurrency, Notification, Alarms 22/55


Concurrent programming Handler

Handler

AsyncTask allows the execution of the code declared in its methods in two
threads: the thread that runs in the background and the UI thread.
Handler is more general as it can be used with any two threads. The use
case is to send code (in the form of Runnable) or information (in the form
of a Message) from a thread to another thread.
These tasks will be executed in the thread associated with the Handler.
The Handler can have associated the UI thread, so the code can have
access to the UI views.
The sender thread needs a reference to the Handler in order to send
Runnable or Message instances.

Topic 4, Concurrency, Notification, Alarms 23/55


Concurrent programming Handler

Handler

We will send a Runnable to the Handler when the sender provides


the code (in the method run ()) that must be executed in the thread
associated with the Handler.
We will send a Message to the Handler when we want the Handler
to execute an action based on the values passed in Message.
If we are interested in receiving messages then we need to make a
class that extends de Handler to overwrite the method
handleMessage(Message m) where we indicate what action should
be performed from the information passed in the Message.

Topic 4, Concurrency, Notification, Alarms 24/55


Concurrent programming Handler

Threads with Looper, Message Queue and Handler


There is a special type of threads in Android that have an associated
Looper and a queue.
Both Message and Runnable can be stored in the queue.
The function of Looper is to continuously inspect the queue, extract the
next element from the queue (or wait until there is one) and once it has
been extracted, perform an action.
There are two ways (mainly) to create a Handler:

With the default constructor, the Handler uses the Looper of the
current thread
With a constructor that provides a Looper.

The UI thread is a thread with Looper.


We can also create an instance of HandlerThread and get its Looper
using getLooper().
Topic 4, Concurrency, Notification, Alarms 25/55
Concurrent programming Handler

Threads with Looper, Message Queue and Handler

Topic 4, Concurrency, Notification, Alarms 26/55


Concurrent programming Handler

Handler: sending a Message

The first thing is to create an object of type Message:


// Using methods of the Handler class
public final Message obtainMessage(...){...}

// Or using methods of the Message class


public static Message obtain(...){...}

Once you have the message you can assign values to its attributes:

arg1 y arg2 to send integer values.


what is an integer used to assign a code to the message (in case we
have several types of messages)
obj is an object that contains the message.
replyTo is of type Messenger that we can use to send messages back.

Topic 4, Concurrency, Notification, Alarms 27/55


Concurrent programming Handler

Handler: sending messages


The class Handler defines methods to send messages:

Topic 4, Concurrency, Notification, Alarms 28/55


Concurrent programming Handler

Looper: extracting a Message

Topic 4, Concurrency, Notification, Alarms 29/55


Concurrent programming Handler

Handler: sending a Runnable


The class Handler defines methods to send Runnable.

postDelayed: executes run delayed delay milliseconds after it has been


sent. Topic 4, Concurrency, Notification, Alarms 30/55
Concurrent programming Handler

Looper: extracting a Runnable

Topic 4, Concurrency, Notification, Alarms 31/55


Notifications

Índice

1 Concurrent programming

2 Notifications

3 Alarms

Topic 4, Concurrency, Notification, Alarms 32/55


Notifications

Show information using Toast


A toast provides simple feedback about an operation in a small popup.
It only fills the amount of space required for the message and the current
activity remains visible and interactive.
Toasts automatically disappear after a timeout.
CharSequence text = "Download completed!";
int duration = Toast.LENGTH_SHORT;
Toast.makeText(getApplicationContext(), text, duration).show();

It is possible to specify a custom layout for the toast using the method
setView:
View layout=getLayoutInflater().inflate(R.layout.toast_layout,null);

Toast toast = new Toast(getApplicationContext());


toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();

To display a message using Toast the activity must be visible.


Topic 4, Concurrency, Notification, Alarms 33/55
Notifications

Notifications

Information that is shown to the user outside of the activities.


Suppose that a task that takes time to complete is executed. The user may
have started another task and therefore the activities associated with the
application are not visible.
Notifications allows the user to be notified in an area reserved for it: the
notification area.
This mechanism allows to inform the user without interfering in what he is
doing.

Topic 4, Concurrency, Notification, Alarms 34/55


Notifications

Notifications

In a notification you can put the following information: title, detail, small
icon, sound, Intent, etc.
To associate an Intent to the notification it is necessary to place it in a
PendingIntent.
For example if we want that when clicking on the notification an activity of
our application is opened:
Intent intent = new Intent(getApplicationContext(),Actividad.class);
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),
requestCode, intent, flag);

The PendingIntent stores an Intent and the context (which includes for
example the permissions).

Topic 4, Concurrency, Notification, Alarms 35/55


Notifications

Notifications

Depending on the component that we are going to activate we must use


the apropriate static method offered by the PendingIntent class:
PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags

PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags

PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flag

PendingIntent getService(Context context, int requestCode, Intent intent, int flags)

The second of the arguments serves to identify the component that makes
the request.

Topic 4, Concurrency, Notification, Alarms 36/55


Notifications

Notifications

As for the argument flag there are several possibilities (declared as static
and public constants in the class PendingIntent):

FLAG_CANCEL_CURRENT: if there already exists a PendingIntent, the


one that already exists before generating the new one must be
canceled.
FLAG_NO_CREATE: if there already exists a PendingIntent, returns
null instead of creating it
FLAG_ONE_SHOT: can be used only once
FLAG_UPDATE_CURRENT: if it already exists, it is maintained but the
data it contains is replaced with the one that is being created.

Topic 4, Concurrency, Notification, Alarms 37/55


Notifications

Notifications
These flags indicate what to do with the existing PendingIntent if we
already have a notification of this type:

Suppose we trigger a notification informing about 2 new mails.


Suppose that the user does not open this notification.
Suppose that 4 new emails are received, what should we do with the
previous notification?
Topic 4, Concurrency, Notification, Alarms 38/55
Notifications

Notifications

When we launch an activity with startActivity from an activity using an


Intent it is added to the existing backstack associated with the task.
When an activity is started from the notification area (using a
PendingIntent) may be there is no task associated to it therefore it is
necessary to specify Intent.FLAG_ACTIVITY_NEW_TASK to create a new
one (if it does not exist) for the activity launched.
This option must be used also if we launch an activity from another
component that is not another activity.
Intent in = ...;
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);.
PendingIntent pi = ...

Topic 4, Concurrency, Notification, Alarms 39/55


Notifications

Notifications

To create the notification you need an object of type


NotificationCompat.Builder. This class is provided by the support
library and must be used to achieve compatibility across devices.
This object allows you to assign the information that will contain the
notification.
NotificationCompat.Builder mBuilderNotif =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setAutoCancel(true) // The notif will be removed from the notification area
.setContentIntent(pi)
.setSound(sound)
.setVibrate(...)
.setContent(...);

Topic 4, Concurrency, Notification, Alarms 40/55


Notifications

Notifications

Once the notification has been created you can: delete, send, etc.
For this the class NotificationManager is used.
Context context = getApplicationContext();

NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIF

// Provide a unique identifier for the notificacion


int id = ...;

// Use notify to send the notification


nm.notify(id,mBuilderNotif.build());

Topic 4, Concurrency, Notification, Alarms 41/55


Notifications

Other examples of services that can be requested

The method Objet getSystemService(String name) of the class


Context allows you to obtain instances from different services. Examples:
LayoutInflater li = (LayoutInflater) contexto.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);

LocationManager lm = (LocationManager) contexto.getSystemService(


Context.LOCATION_SERVICE);

Vibrator vib = (Vibrator) contexto.getSystemService(Context.VIBRATOR_SERVICE);

SensorManager sm = (SensorManager) contexto.getSystemService(Context.SENSOR_SERVICE)

...

http://developer.android.com/reference/android/content/Context.html

Topic 4, Concurrency, Notification, Alarms 42/55


Alarms

Índice

1 Concurrent programming

2 Notifications

3 Alarms

Topic 4, Concurrency, Notification, Alarms 43/55


Alarms

Alarms

They allow launch Intent at a specific time or at certain intervals.


This allows that although the application is not running, a certain task can
be executed.
Once registered, alarms remain active even if the device is sleeping.
If the device goes off the alarms that were registered are cancelled.

Topic 4, Concurrency, Notification, Alarms 44/55


Alarms

Alarms

You have to take into account some recommendations when using alarms:

If you are activating a service that connects to a server you should


mantain a low activation frequency to do not drain the battery and do
not overload the servers.
If an application is distributed and an alarm is set at a fixed time to
perform a call on a server, a denial of service may occur. In these
cases, a random temporal displacement can be introduced.
You can specify that the time provided is not accurate. This allows the
system to group several alarms that are in an interval. This would
avoid awakening the system several times in a small interval to
decrease energy consumption.

Topic 4, Concurrency, Notification, Alarms 45/55


Alarms

Type of watch used by the alarm

There are two kinds:

Elapsed real time (ELAPSED_REALTIME)time since the system was


last started. This option is appropriate if we want the alarm to be
triggered every certain interval of time.
Real time (RTC) time set by the device (depends on the configuration
of the device: time zone). This option is only appropriate if the alarm
must be activated at a specific time (for instance calendar events). If
the user changes the clock this will affect the alarm.

It is recommended to use the first type whenever possible.

Topic 4, Concurrency, Notification, Alarms 46/55


Alarms

Alarms

In addition, the two previous types have two subtypes:

A version that wakes up the CPU of the device even if it is with the
screen off (WAKEUP).
A version that waits for the device to wake up to activate the alarm.

Topic 4, Concurrency, Notification, Alarms 47/55


Alarms

Alarms

Therefore, the four types are (attributes declared as static in the class
AlarmManager):

ELAPSED_REALTIME launches the PendingIntent depending on the


time elapsed since the device was started and if the alarm is activated
when the device is "sleepingït does not wake it up.
ELAPSED_REALTIME_WAKEUP launches the PendingIntent according
to the time elapsed since the device and activates the device if it is
"sleeping".

RTC launches the PendingIntent at the specified time and if the


alarm is activated when the device is "sleepingït does not wake it up.
RTC_WAKEUP launches PendingIntent at the specified time and
activates the device if it is "sleeping".

Topic 4, Concurrency, Notification, Alarms 48/55


Alarms

Alarms

To register alarms, an object of type AlarmManager is used.


To obtain an object of this type:
AlarmManager am = (AlarmManager)getApplicationContext().getSystemService(Context.ALA

Topic 4, Concurrency, Notification, Alarms 49/55


Alarms

Non-repetitive alarms

Once you have an object of type AlarmManager you can use the method:
void set(int tipo, long activarMillis, PendingIntent operacion)

to create the alarm.


The documentation indicates that from the API 19 (KITKAT) it is possible
that the alarms established in this way are activated inaccurately (not
exactly when indicated).

Topic 4, Concurrency, Notification, Alarms 50/55


Alarms

Non-repetitive alarms

In addition, they offer other methods that guarantee accuracy such as:
// Set a temporary window to activate the alarm
setWindow(int type, long windowStartMillis, long windowLengthMillis, PendingIntent a

// The exact time is set to activate the alarm


setExact(int type, long whenMillis, PendingIntent action)

Topic 4, Concurrency, Notification, Alarms 51/55


Alarms

Repetitive alarms

To establish a repetitive alarm you must provide the following information:

The type of clock for the alarm


When the alarm is triggered
The shooting interval: for example once a day, every hour, etc.
A PendingIntent to be launched when the alarm is triggered.

Topic 4, Concurrency, Notification, Alarms 52/55


Alarms

Repetitive alarms

If the alarm is repetitive you can use the methods of AlarmManager:


void setRepeating(int type, long millisStart, long millisInterval,
PendingIntent action)

where interval indicates the time that must elapse between activations.
void setInexactRepeating(int type, long millisStart, long millisInterval,
PendingIntent action)

where it is left to the system the decision of when to activate the alarm
within the interval (in this way the system could group the alarms not to be
activating the device).

Topic 4, Concurrency, Notification, Alarms 53/55


Alarms

Cancel an alarm

To cancel the alarm, the method cancel of the class AlarmManager by


passing the PendingIntent that was used to activate it:
// Cancel the alarm
if (alarmMgr!= null) {
alarmMgr.cancel(alarmIntent);
}

Topic 4, Concurrency, Notification, Alarms 54/55


Alarms

Strategy to set an alarm at boot

When the device is turned off, all alarms are cleared.


If we want our application to set the alarms again, we can include a
BroadcastReceiver in our application and register to be notified when
the system finishes boot. In the code we can set the alarm again.
In a later topic we will see this type of component.

Topic 4, Concurrency, Notification, Alarms 55/55

You might also like