You are on page 1of 40

Mobile Computing

Lecture #06
Services
Previous Lecture
Android Intents
Today’s Lecture
Services
Implementing a Service
Service Lifecycle
Service Examples
AsyncTask
IntentService
Service
A service is a component that runs in the background to perform long
running operations without needing to interact with the user and its
work even if the application is destroyed.
An application component can start a service and it continue to run in
the background even if you switch to another application
It runs in main application thread until it is specified otherwise
A Service in Android can be started from an Activity, from a
Broadcast receiver and other services too
Just like an Activity, a Service must be declared inside
AndroidManifest.xml file
Service States
A Service can essentially two states:
1. Started (Un-Bound)
2. Bound
Started
 A service is started when an application component, such as an activity, starts it by calling
startService()
 Once started, a service can run in the background indefinitely, even if the component that started it
is destroyed.
 It is stopped by using the stopService() method. The service can also stop itself by calling the
stopSelf() method.
Bound
 A service is bound when an application component binds to it by calling bindService()
 A bound service offers a client-server interface that allows components to interact with the service,
send requests and get results
 Even bound service can communicate across processes with Inter Process Communication (IPC)#
 The client can unbind the service by calling the unbindService() methos
startService()
vs
bindService()
A service is start by calling startService() method and it is stop by
stopService() method. A service can stop itself by calling the stopSelf()
method.
A service is bound, when another component calls bindService()
method. The client can unbind the service by calling the
unbindService() method. The service cannot be stopped until the client
unbind the service.
Service
Main objective of a service is to run in background and perform some long
running task not requiring user to interact with it
It runs in main application thread until it is specified otherwise
A service can be implemented using its lifecycle’s callback methods
public void onCreate()
public void onStartCommand()
public void onBind()
public void onDestroy()
A Service in Android can be started from an Activity, from a Broadcast receiver
and other services too
Just like an Activity, a Service must be declared inside AndroidManifest.xml file
Service …
A service that requires to perform CPU intensive tasks (MP3 playback, intense
calculations, process animations etc.) or blocking operations, it must create its
own thread to perform that task
Implementing a Service
A class can be implemented as a Service:
public class TestService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
We have to implement only one method called onBind()
Similar to an Activity, a Service has its lifecycle and we can override some
callback methods so that we can handle its different states
Service Lifecycle … Code Example
public class TestService extends Service {
    @Override
    public void onCreate() {       
        super.onCreate();
    }
    @Override
    public void onDestroy() {       
        super.onDestroy();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {       
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public IBinder onBind(Intent arg0) {       
        return null;
    }
}
Service Lifecycle
 The method onCreate() is called only one time
when the Service has to created. Android system
calls this method
 onStartCommand() is the most important method
because it is called when we required to start the
Service
 In this method we have the Intent passed at
time we run the Service, in this way we can
exchange some information with the Service
 Here, we implement our logic that can be
execute directly inside this method if it isn’t
time expensive otherwise we can create a
thread
 One can observe that this method requires us to
return an Integer as result. This integer represents
how the Service should be handled by the OS
Service … Example … MyService1.Java
public class MyService1 extends Service {
public IBinder onBind(Intent intent){
return null;
}

public int onStartCommand(Intent intent, int flags, int startId){


Toast.makeText(MyService1.this, "Service Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}

public int onStart(Intent intent, int flags, int startId){


Toast.makeText(MyService1.this, "Service Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}

public void onDestroy(){


Toast.makeText(MyService1.this, "Service Stopped",
Toast.LENGTH_LONG).show();
}
}
Service … Example … MainActivity.java
public class MainActivity extends AppCompatActivity
implements View.OnClickListener {
Button start_stop_button;
Intent serviceIntent;
@Override public void onClick(View view){
protected void onCreate(Bundle savedInstanceState) { String string =
super.onCreate(savedInstanceState); ((Button)view).getText().toString();
setContentView(R.layout.activity_main); String buttonText =
start_stop_button = findViewById(R.id.start_stop);
getString(R.string.start);
start_stop_button.setOnClickListener(this); if(string.equals(buttonText)){
serviceIntent = new Intent(this, MyService1.class); startService(serviceIntent);
} start_stop_button.setText(R.string.stop);
}
else{
stopService(serviceIntent);
start_stop_button.setText(R.string.start);
}
}
}
Service … Example … AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.imran.serviceapp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
<service android:name="MyService1" android:enabled="true"/>
</application>
</manifest>
Service … Example … Execution
Service … Example … Summary
Above application does not do anything very useful
It simply creates and shows a Toast while starting service and stopping
service
To make things more meaningful, we create another example in which we
want to simulate a long running task e.g. downloading a file from internet
Service … Example2 … MyService2.Java
public class MyService1 extends Service {
public IBinder onBind(Intent intent){
return null;
}

public int onStartCommand(Intent intent, int flags, int startId){


Toast.makeText(MyService1.this, "Service Started", Toast.LENGTH_LONG).show();
try{
int result = downloadFile(new URL("http://mywebsite.com/myfile.pdf"));
Toast.makeText(this, "Downloaded "+result+" bytes", Toast.LENGTH_LONG).show();
}catch (MalformedURLException exception){
exception.printStackTrace();
}
return START_STICKY;
}
Service … Example … MyService2.Java
public void onDestroy(){
Toast.makeText(MyService2.this, "Service Stopped", Toast.LENGTH_LONG).show();
}

public int downloadFile(URL url){


try{
Thread.sleep(7000);
}catch (InterruptedException exception){
exception.printStackTrace();
}
return 2000;
}
}
Service … Example2 … MainActivity.java
public class MainActivity extends AppCompatActivity
implements View.OnClickListener {
Button start_stop_button;
Intent serviceIntent;
@Override public void onClick(View view){
protected void onCreate(Bundle savedInstanceState) { String string =
super.onCreate(savedInstanceState); ((Button)view).getText().toString();
setContentView(R.layout.activity_main); String buttonText =
start_stop_button = findViewById(R.id.start_stop);
getString(R.string.start);
start_stop_button.setOnClickListener(this); if(string.equals(buttonText)){
serviceIntent = new Intent(this, MyService2.class); startService(serviceIntent);
} start_stop_button.setText(R.string.stop);
}
else{
stopService(serviceIntent);
start_stop_button.setText(R.string.start);
}
}
}
Service … Example2 … AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.imran.serviceapp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="MyService1" android:enabled="true"/>
<service android:name="MyService2" android:enabled="true"/>
</application>
</manifest>
Service … Example2 … Execution
Service … Example2
We created another example in which we simulated to download a file
from internet (for that purpose we called Thread.sleep(7000) method)
One noticed that Thread.sleep(7000) caused our activity to pause for
seven seconds
During that time our activity was not responsive at all
Even the output of below statement was not shown
Toast.makeText(MyService2.this, "Service Started", Toast.LENGTH_LONG).show();
It demonstrates us a very important point in this regard i.e. Service runs on the
same thread as the activity (called main thread)
We can use AsyncTask class to perform background tasks asynchronously
Service … Example3 … MyService3.Java
public class MyService3 extends Service {
public int onStartCommand(Intent intent, int flags, int startId){
Toast.makeText(MyService3.this, "Service Started", Toast.LENGTH_LONG).show();
try{
new BackgroundTask(this).execute(
new URL("http://www.abc.com/file1.pdf"),
new URL("http://www.abc.com/file1.pdf"));
stopSelf();
}catch (MalformedURLException exception){
exception.printStackTrace();
}
return START_STICKY;
}

public void onDestroy(){


Toast.makeText(MyService3.this, "Service Stopped", Toast.LENGTH_LONG).show();
}
}
Service … Example3 … MainActivity.java
public class MainActivity extends AppCompatActivity
implements View.OnClickListener {
Button start_stop_button;
Intent serviceIntent;
@Override public void onClick(View view){
protected void onCreate(Bundle savedInstanceState) { String string =
super.onCreate(savedInstanceState); ((Button)view).getText().toString();
setContentView(R.layout.activity_main); String buttonText =
start_stop_button = findViewById(R.id.start_stop);
getString(R.string.start);
start_stop_button.setOnClickListener(this); if(string.equals(buttonText)){
serviceIntent = new Intent(this, MyService3.class); startService(serviceIntent);
} start_stop_button.setText(R.string.stop);
}
else{
stopService(serviceIntent);
start_stop_button.setText(R.string.start);
}
}
}
Service … Example3 … AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="MyService1" android:enabled="true"/>
<service android:name="MyService2" android:enabled="true"/>
<service android:name="MyService3" android:enabled="true"/>
</application>
</manifest>
Service … Example3 … BackgroundTask.java
public class BackgroundTask extends AsyncTask<URL, Integer, Long> {
private Context myContext;
public BackgroundTask(Context context){
myContext = context;
}
protected Long doInBackground(URL ... urls){
int count = urls.length;
long totalBytesDownloaded = 0;
for (int i=0; i<count; i++){
totalBytesDownloaded += downloadFile(urls[i]);
publishProgress((int)((i+1)/(double)count*100));
}
return totalBytesDownloaded;
}
protected void onProgressUpdate(Integer... progress){
Toast.makeText(myContext, String.valueOf(progress[0])+" % downloaded",
Toast.LENGTH_LONG).show();
}
Service … Example3 … BackgroundTask.java …
public int downloadFile(URL url){
try{
Thread.sleep(7000);
}catch (InterruptedException exception){
exception.printStackTrace();
}
return 2000;
}

protected void onPostExecute(Long result){


Toast.makeText(myContext, "Downloaded "+result+" bytes",
Toast.LENGTH_LONG ).show();
}
}
Repeated Tasks using a Service
In addition to performing long running tasks, a service can be used to
perform a task repeatedly
For example, one may write a alarm service that runs in background
persistently and rings alarm on a particular time daily
In this case, the service may need to periodically execute some code
to check whether alarm time has been reached
To repeatedly execute a block of code at a regular interval, one can
always use Timer instance within a Service class
Following is an example of using Timer instance in a Service:
Service … Example4 … MyService4.Java
public class MyService4 extends Service {
static final UPDATE_INTERVAL = 4000;
Timer timer = new Timer();
private int counter = 0;

public int onStartCommand(Intent intent, int flags, int startId){


Toast.makeText(MyService3.this, "Service Started", Toast.LENGTH_LONG).show();
doSomethingRepeatedly();
try{
new BackgroundTask(this).execute(
new URL("http://www.abc.com/file1.pdf"),
new URL("http://www.abc.com/file2.pdf"),
new URL("http://www.abc.com/file3.pdf"));
stopSelf();
}catch (MalformedURLException exception){
exception.printStackTrace();
}
return START_STICKY;
}
Service … Example4 … MyService4.Java

public void doSomethingRepeatedly(){


timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Log.d("Service 04", String.valueOf(++counter));
//Toast.makeText(MyService4.this, "Repeated Task: "+counter, Toast.LENGTH_SHORT).show();
}
}, 1, UPDATE_INTERVAL);
}

public void onDestroy(){


Toast.makeText(MyService3.this, "Service Stopped", Toast.LENGTH_LONG).show();
if(timer != null){
timer.cancel();
}
}
}
Service … Example4 … MainActivity.java
public class MainActivity extends AppCompatActivity
implements View.OnClickListener {
Button start_stop_button;
Intent serviceIntent;
@Override public void onClick(View view){
protected void onCreate(Bundle savedInstanceState) { String string =
super.onCreate(savedInstanceState); ((Button)view).getText().toString();
setContentView(R.layout.activity_main); String buttonText =
start_stop_button = findViewById(R.id.start_stop);
getString(R.string.start);
start_stop_button.setOnClickListener(this); if(string.equals(buttonText)){
serviceIntent = new Intent(this, MyService4.class); startService(serviceIntent);
} start_stop_button.setText(R.string.stop);
}
else{
stopService(serviceIntent);
start_stop_button.setText(R.string.start);
}
}
}
Service … Example3 … AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="MyService1" android:enabled="true"/>
<service android:name="MyService2" android:enabled="true"/>
<service android:name="MyService3" android:enabled="true"/>
<service android:name="MyService4" android:enabled="true"/>
</application>
</manifest>
Service … Example4 … BackgroundTask1.java
public class BackgroundTask extends AsyncTask1<URL, Integer, Long> {
private Context myContext;
public BackgroundTask(Context context){
myContext = context;
}
protected Long doInBackground(URL ... urls){
int count = urls.length;
long totalBytesDownloaded = 0;
for (int i=0; i<count; i++){
totalBytesDownloaded += downloadFile(urls[i]);
publishProgress((int)((i+1)/(double)count*100));
}
return totalBytesDownloaded;
}
protected void onProgressUpdate(Integer... progress){
Toast.makeText(myContext, String.valueOf(progress[0])+" % downloaded",
Toast.LENGTH_LONG).show();
}
Service … Example4 … BackgroundTask.java …
public int downloadFile(URL url){
try{
Thread.sleep(7000);
}catch (InterruptedException exception){
exception.printStackTrace();
}
return 2000;
}

protected void onPostExecute(Long result){


Toast.makeText(myContext, "Downloaded "+result+" bytes",
Toast.LENGTH_LONG ).show();
}
}
Repeated Tasks using a Service …
We create a Timer instance and use it to repeat a log entry after every four
seconds (UPDATE_INTERVAL)
public void doSomethingRepeatedly(){
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Log.d("Service 04", String.valueOf(++counter));
}
}, 1, UPDATE_INTERVAL);
}
Second parameter to scheduleAtFixedRate() function is time interval (in
mili-seconds) before timer runs very first time
Third parameter to scheduleAtFixedRate() function is time interval (in
mili-seconds) between subsequent executions
IntentService
A service that runs in a separate thread and stops automatically when task
is finished
For example, downloading some file, executing some computational task
etc.
IntentService … Example5
public class IntentService1 extends IntentService {
Thread thread = new Thread();
public IntentService1(){
super("IntentService1");
}

protected void onHandleIntent(Intent intent){


thread.start();
Log.d("IntentService 01:", "Started");
try{
int result = downloadFile(new URL("http://www.amazon.com/file1.pdf"));
Log.d("IntentService 01:", "Downloaded "+result+" bytes.");
}catch (MalformedURLException exc){
exc.printStackTrace();
}
}
IntentService … Example5 …
public int downloadFile(URL url){
try{
thread.sleep(6000);
}catch (InterruptedException e){
e.printStackTrace();
}
return 2000;
}
}
IntentService … Example5 …

Extend your class from IntentService if you want your background code to
execute in separate thread
Implement constructor of class calling super constructor using a String
Implement onHandleIntent(Intent), it is executed in a worker thread
When the code has finished executing, thread ends terminating the
IntentService automatically

You might also like