This shows you the differences between two versions of the page.
smd:laboratoare:03 [2020/03/09 06:12] vasile.cosovanu Moved tasks through lab |
smd:laboratoare:03 [2021/04/08 16:57] (current) adriana.draghici [Using Intent Services] |
||
---|---|---|---|
Line 11: | Line 11: | ||
[[https://developer.android.com/guide/components/services|Services]] are the application components that execute logic even in background, when the activities of the app are not visible. Services do not have an UI and run on the //main thread// of the hosting process. | [[https://developer.android.com/guide/components/services|Services]] are the application components that execute logic even in background, when the activities of the app are not visible. Services do not have an UI and run on the //main thread// of the hosting process. | ||
- | :!: Throughout this lab we refer to background(not visible) and foreground(visible) in terms of components' lifecycle not in terms of threading. | + | :!: Throughout this lab we refer to **background** (not visible) and **foreground** (visible) in terms of components' lifecycle not in terms of threading. |
**Types:** | **Types:** | ||
Line 83: | Line 83: | ||
====Start a service==== | ====Start a service==== | ||
+ | |||
<code java> | <code java> | ||
Line 114: | Line 115: | ||
</code> | </code> | ||
- | === Tasks === | + | :!: If your project is configured for versions higher than Oreo, there's no need to perform the check for Oreo. |
- | For better code readability and to avoid errors caused by typos please define all the names of the intent actions and their parameters in constant fields. Not doing this can lead to lower grades for those tasks. | + | |
+ | ====Start foreground service==== | ||
+ | * Examples: [[https://developer.android.com/guide/components/foreground-services#java|documentation]], [[https://androidwave.com/foreground-service-android-example/|tutorial]] | ||
+ | * Create a persistent notification like in the links provided above. | ||
+ | * Call ''startForeground'' | ||
+ | |||
+ | <code java> | ||
+ | // In LocationService | ||
+ | public void startLocationTracking(int interval) { | ||
+ | Log.d(TAG, "Location tracking is active"); | ||
+ | Notification notification = buildNotification(); | ||
+ | setServiceForeground(true, notification); | ||
+ | } | ||
+ | |||
+ | private void setServiceForeground(Boolean serviceIsForeground, Notification notification) { | ||
+ | if (this.serviceIsForeground != serviceIsForeground) { | ||
+ | this.serviceIsForeground = serviceIsForeground; | ||
+ | if (serviceIsForeground) { | ||
+ | startForeground(LOCATION_NOTIFICATION_ID, notification); | ||
+ | } else { | ||
+ | stopForeground(true); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ==== Tasks details ==== | ||
+ | |||
+ | Create a new project with a basic MainActivity, supporting versions > Oreo. You will use this project for all the tasks in this lab. | ||
+ | |||
+ | For better code readability and to avoid errors caused by typos please define all the names of the intent actions and their parameters in constant fields. Place the constants in the classes they are related to (e.g. intent actions for a component should be declared in that class/file if in Kotlin). Provide static methods for obtaining a component's starting intent. | ||
<note tip>In the following tasks observe the lifecycle of the components involved. See what happens when the activity is paused, destroyed, when the app is destroyed.</note> | <note tip>In the following tasks observe the lifecycle of the components involved. See what happens when the activity is paused, destroyed, when the app is destroyed.</note> | ||
Line 122: | Line 153: | ||
=== Task 1 StartedService (2p) === | === Task 1 StartedService (2p) === | ||
- | In this task we will create a StartedService which prints a message using a Toast. | + | In this task we will create a Foreground Started Service which prints a message using a Toast. |
- | * Create a new project and add a new Service, and name it //MyStartedService//. | + | * Add a new Service, and name it //MyStartedService//. |
* In //MyStartedService// override ''onCreate'', ''onStartCommand'', ''onBind'' and ''onDestroy'' and add a debug log message with the name of the method and the name of the current thread | * In //MyStartedService// override ''onCreate'', ''onStartCommand'', ''onBind'' and ''onDestroy'' and add a debug log message with the name of the method and the name of the current thread | ||
* Start the service as //START_NOT_STICKY// | * Start the service as //START_NOT_STICKY// | ||
Line 130: | Line 161: | ||
====Bind to a service==== | ====Bind to a service==== | ||
- | * implement a connection callback | + | * Implement a **connection callback** |
- | * call ''bindService'' | + | * Call ''bindService'' |
- | * override the ''onBind'' method in the service | + | * Override the ''onBind'' method in the service |
- | * call ''unbindService'' when you no longer need to be bound to the service | + | * Call ''unbindService'' when you no longer need to be bound to the service |
<code java> | <code java> | ||
Line 180: | Line 211: | ||
=== Task 2 BoundService (3p) === | === Task 2 BoundService (3p) === | ||
- | In this task we will create a BoundService from which will take a value and print it with a Toast. | + | In this task we will create a BoundService that the activity interacts with to show the current date in a Toast message. |
- | * Add a new //Service//, and name it //MyBoundService.// | + | * Add a new //Service//, and name it //DateBoundService.// |
- | * In the service override ''onCreate'', ''onBind'', ''onUnbind'' and ''onDestroy'' and add a debug log message with the name of the method and the name of the current thread | + | * In the service override ''onCreate'', ''onBind'', ''onUnbind'' and ''onDestroy'' and add a debug log message with the name of the method and the name of the current thread in each of them. |
* In the service write a method ''getCurrentDate()'' that will return a string with the current date | * In the service write a method ''getCurrentDate()'' that will return a string with the current date | ||
* In //MainActivity// bind the service in ''onCreate'' and unbind it in ''onDestroy'' | * In //MainActivity// bind the service in ''onCreate'' and unbind it in ''onDestroy'' | ||
* In //MainActivity// add a button that will call ''service.getCurrentDate()'' | * In //MainActivity// add a button that will call ''service.getCurrentDate()'' | ||
- | * Print the date using a Toast message | + | * Show the date using a Toast message |
- | ====Start foreground service==== | ||
- | * create a persistent notification (see [[https://proandroiddev.com/deep-dive-into-android-services-4830b8c9a09|example]]) | ||
- | * call ''startForeground'' | ||
- | |||
- | <code java> | ||
- | // In LocationService | ||
- | public void startLocationTracking(int interval) { | ||
- | Log.d(TAG, "blabla"); | ||
- | Notification notification = buildNotification(); | ||
- | setServiceForeground(true, notification); | ||
- | } | ||
- | |||
- | private void setServiceForeground(Boolean serviceIsForeground, Notification notification) { | ||
- | if (this.serviceIsForeground != serviceIsForeground) { | ||
- | this.serviceIsForeground = serviceIsForeground; | ||
- | if (serviceIsForeground) { | ||
- | startForeground(LOCATION_NOTIFICATION_ID, notification); | ||
- | } else { | ||
- | stopForeground(true); | ||
- | } | ||
- | } | ||
- | } | ||
- | </code> | ||
==== Using Intent Services==== | ==== Using Intent Services==== | ||
- | * extend the ''IntentService'' class | + | * Extend the ''IntentService'' class |
- | * implement the [[https://developer.android.com/reference/android/app/IntentService.html#onHandleIntent(android.content.Intent)|onHandleIntent]] method | + | * Implement the [[https://developer.android.com/reference/android/app/IntentService.html#onHandleIntent(android.content.Intent)|onHandleIntent]] method |
* in the component that wants to run the service: | * in the component that wants to run the service: | ||
* create an intent: ''Intent intent = new Intent(context, MyIntentService.class);'' | * create an intent: ''Intent intent = new Intent(context, MyIntentService.class);'' | ||
* start the service: ''startService(intent)'' | * start the service: ''startService(intent)'' | ||
- | * if we want to send a response from the IntentService to the activity, we can broadcast the result using intents and register a broadcast receiver for them. | + | * If we want to send a response from the IntentService to the activity, we can broadcast the result using intents and register a broadcast receiver for them. |
+ | /* | ||
+ | TODO INTENT SERVICE IS DEPRECATED, LEAVE THE TEXT< ADD A WARNING AND REMOVE THE EXERCISE | ||
+ | */ | ||
=== Task 3 LuckyIntentService (2p) === | === Task 3 LuckyIntentService (2p) === | ||
- | * From the main activity start an intent service that gives you money :) | + | * From the MainActivity start an intent service that gives you money :) |
* The intent service generates a random number representing the money and logs it | * The intent service generates a random number representing the money and logs it | ||
- | * you can use [[https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadLocalRandom.html|ThreadLocalRandom]] for generating a number within two limits (e.g. between 10 and 10000). | + | * you can use [[https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/concurrent/ThreadLocalRandom.html|ThreadLocalRandom]] for generating a number within two limits (e.g. between 10 and 10000). |
- | * perform the null and action checks for the intent received by the service | + | * validate the intent's action (not null, the action is the one we expect) |
* Log the thread running the service | * Log the thread running the service | ||
- | === Task 4 Send message from service (3p) === | + | === Task 4 Send a message from service (3p) === |
* Show the user the result of the ''LuckyIntentService'' (the money they won) | * Show the user the result of the ''LuckyIntentService'' (the money they won) | ||
- | * Define a BroadcastReceiver that shows a toast to the user "You won x euro", where x is the number received in the intent. | + | * Define a **local BroadcastReceiver** that shows a toast to the user "You won x euro", where x is the number received in the intent. |
- | * The main activity registers and unregisters the receiver | + | * The ''MainActivity'' registers and unregisters the receiver |
* The ''LuckyIntentService'' sends a broadcast with a given Intent | * The ''LuckyIntentService'' sends a broadcast with a given Intent | ||
* The broadcast receiver receives the intent and shows the toast | * The broadcast receiver receives the intent and shows the toast | ||
* Use ''LocalBroadcastManager'' to register, unregister and send broadcasts, as presented in [[smd:laboratoare:02#broadcast_receivers|Lab 2]] | * Use ''LocalBroadcastManager'' to register, unregister and send broadcasts, as presented in [[smd:laboratoare:02#broadcast_receivers|Lab 2]] | ||
- | * Perform the null and action checks for the intent received by the broadcast receiver | + | * validate the intent's action (not null, the action is the one we expect) |
- | ===== Resources ===== | ||