Android start service from another app

Foreground services

Foreground services perform operations that are noticeable to the user.

Foreground services show a status bar notification, so that users are actively aware that your app is performing a task in the foreground and is consuming system resources. The notification cannot be dismissed unless the service is either stopped or removed from the foreground.

Devices that run Android 12 (API level 31) or higher provide a streamlined experience for short-running foreground services. On these devices, the system waits 10 seconds before showing the notification associated with a foreground service. There are a few exceptions; several types of services always display a notification immediately.

Examples of apps that would use foreground services include the following:

  • A music player app that plays music in a foreground service. The notification might show the current song that is being played.
  • A fitness app that records a user’s run in a foreground service, after receiving permission from the user. The notification might show the distance that the user has traveled during the current fitness session.

You should only use a foreground service when your app needs to perform a task that is noticeable by the user even when they’re not directly interacting with the app. If the action is of low enough importance that you want to use a minimum-priority notification, create a background task instead.

This document describes the required permission for using foreground services, how to start a foreground service and remove it from the background, how to associate certain use cases with foreground service types, and the access restrictions that take effect when you start a foreground service from an app that’s running in the background.

Services that show a notification immediately

If a foreground service has at least one of the following characteristics, the system shows the associated notification immediately after the service starts, even on devices that run Android 12 or higher:

  • The service is associated with a notification that includes action buttons.
  • The service has a foregroundServiceType of mediaPlayback , mediaProjection , or phoneCall .
  • The service provides a use case related to phone calls, navigation, or media playback, as defined in the notification’s category attribute.
  • The service has opted out of the behavior change by passing FOREGROUND_SERVICE_IMMEDIATE into setForegroundServiceBehavior() when setting up the notification.

Request the foreground service permission

Apps that target Android 9 (API level 28) or higher and use foreground services must request the FOREGROUND_SERVICE permission, as shown in the following code snippet. This is a normal permission, so the system automatically grants it to the requesting app.

Start a foreground service

Before you request the system to run a service as a foreground service, start the service itself:

Kotlin

Inside the service, usually in onStartCommand() , you can request that your service run in the foreground. To do so, call startForeground() . This method takes two parameters: a positive integer that uniquely identifies the notification in the status bar and the Notification object itself.

Note: The status bar notification must use a priority of PRIORITY_LOW or higher. If your app attempts to use a notification that has a lower priority, the system adds a message to the notification drawer, alerting the user to the app’s use of a foreground service.

Here is an example:

Kotlin

Restrictions on background starts

Apps that target Android 12 (API level 31) or higher can’t start foreground services while running in the background, except for a few special cases. If an app tries to start a foreground service while the app is running in the background, and the foreground service doesn’t satisfy one of the exceptional cases, the system throws a ForegroundServiceStartNotAllowedException .

Check whether your app performs background starts

To better understand when your app attempts to launch a foreground service while running in the background, you can enable notifications that appear each time this behavior occurs. To do so, execute the following ADB command on the development machine connected to your test device or emulator:

Update your app’s logic

If you discover that your app starts foreground services while running from the background, update your app’s logic to use WorkManager. To view an example of how to update your app, look through the WorkManagerSample on GitHub.

Exemptions from background start restrictions

In the following situations, your app can start foreground services even while your app is running in the background:

  • Your app transitions from a user-visible state, such as an activity.
  • Your app can start an activity from the background, except for the case where the app has an activity in the back stack of an existing task.

Your app receives a high-priority message using Firebase Cloud Messaging.

Note: When your app is in the frequent bucket or a more restrictive bucket, your high-priority FCM messages might be downgraded to normal priority. If the message’s priority is downgraded, your app can’t start a foreground service. To check the priority of an FCM message that your app receives, call getPriority() .

The user performs an action on a UI element related to your app. For example, they might interact with a bubble, notification, widget, or activity.

Your app invokes an exact alarm to complete an action that the user requests.

Your app is the device’s current input method.

Your app receives an event that’s related to geofencing or activity recognition transition.

Your app receives the ACTION_TIMEZONE_CHANGED , ACTION_TIME_CHANGED , or ACTION_LOCALE_CHANGED intent action in a broadcast receiver.

Your app receives a Bluetooth broadcast that requires the BLUETOOTH_CONNECT or BLUETOOTH_SCAN permissions.

Apps with certain system roles or permission, such as device owners and profile owners.

Your app uses the Companion Device Manager and declares the REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND permission or the REQUEST_COMPANION_RUN_IN_BACKGROUND permission. Whenever possible, use REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND .

The user turns off battery optimizations for your app. You can help users find this option by sending them to your app’s App info page in system settings. To do so, invoke an intent that contains the ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent action.

Remove a service from the foreground

To remove the service from the foreground, call stopForeground() . This method takes a boolean, which indicates whether to remove the status bar notification as well. Note that the service continues to run.

If you stop the service while it’s running in the foreground, its notification is removed.

Declare foreground service types

If your app targets Android 10 (API level 29) or higher and accesses location information in a foreground service, declare the location foreground service type as an attribute of your component.

If your app targets Android 11 (API level 30) or higher and accesses the camera or microphone in a foreground service, declare the camera or microphone foreground service types, respectively, as attributes of your component.

By default, when you call startForeground() at runtime, the system allows access to each of the service types that you declare in the app manifest. You can choose to limit access to a subset of the declared service types, as shown in the code snippets within the following sections.

Example using location and camera

If a foreground service in your app needs to access the device’s location and camera, declare the service as shown in the following snippet:

At runtime, if the foreground service only needs access to a subset of the types declared in the manifest, you can limit the service’s access using the logic in the following code snippet:

Kotlin

Example using location, camera, and microphone

If a foreground service needs to access location, the camera, and the microphone, declare the service as shown in the following snippet:

At runtime, if the foreground service only needs access to a subset of the types declared in the manifest, you can limit the service’s access using the logic in the following code snippet:

Kotlin

Add foreground service types of Work Manager workers

If your app uses Work Manager and has a long-running worker that requires access to location, camera, or microphone, follow the steps to add a foreground service type to a long-running worker, and specify the additional or alternative foreground service types that your worker uses. You can choose from the following foreground service types:

Restricted access to location, camera, and microphone

To help protect user privacy, Android 11 (API level 30) introduces limitations to when a foreground service can access the device’s location, camera, or microphone. When your app starts a foreground service while the app is running in the background, the foreground service has the following limitations:

  • Unless the user has granted the ACCESS_BACKGROUND_LOCATION permission to your app, the foreground service cannot access location.
  • The foreground service cannot access the microphone or camera.

Exemptions from the restrictions

In some situations, even if a foreground service is started while the app is running in the background, it can still access location, camera, and microphone information while the app is running in the foreground («while-in-use»). In these same situations, if the service declares a foreground service type of location and is started by an app that has the ACCESS_BACKGROUND_LOCATION permission, this service can access location information all the time, even when the app is running in the background.

The following list contains these situations:

  • The service is started by a system component.
  • The service is started by interacting with app widgets.
  • The service is started by interacting with a notification.
  • The service is started as a PendingIntent that is sent from a different, visible app.
  • The service is started by an app that is a device policy controller that is running in device owner mode.
  • The service is started by an app which provides the VoiceInteractionService .
  • The service is started by an app that has the START_ACTIVITIES_FROM_BACKGROUND privileged permission.

Determine which services are affected in your app

When testing your app, start its foreground services. If a started service has restricted access to location, microphone, and camera, the following message appears in Logcat:

Content and code samples on this page are subject to the licenses described in the Content License. Java is a registered trademark of Oracle and/or its affiliates.

Источник

Android Services: Getting Started

Learn about Android Services and the differences between foreground, background and bound services.

Version

  • Kotlin 1.4, Android 5.0, Android Studio 4.2

Many Android apps have features that take a long time to run, like downloading content or updating a remote database. If developers don’t handle these features properly, they slowly clutter the main thread, creating memory leaks and inconsistencies in the results. This leads to a bad user experience.

Fortunately, there’s a solution for handling these actions: Android Services. This is a special type of application component that’s designed to handle repetitive and long running jobs.

In this tutorial, you’ll learn:

  • What Android Services are and how to declare them in the Manifest file.
  • How to use a foreground service while displaying a notification to the user.
  • What is it with background processing for complex work that isn’t related to the UI.
  • How to use a bound service.

Getting Started

Download the starter project by using the Download Materials button at the top or bottom of this tutorial.

For this tutorial, you’ll use the Memo app. Memo is a game that challenges the user to match cards in the shortest possible time. Additionally, the user can listen to audio tracks while they play.

The game has four levels: Beginner, Intermediate, Advanced and Expert. The higher the level, the more cards to match. After the user finishes the expert level, they complete the game. Do you dare to try your luck? :]

Currently, the app only lets the user start a game and manipulate the audio tracks. Once you start a game, you’ll be able to quit, preview game cards and track the time elapsed since the game started.

Open the project in Android Studio and get familiar with the files. When you’re done, build and run it on a device/emulator to see how the app looks.

Play the game by pressing PLAY BEGINNER LEVEL. At this point, you can match the cards but there’s no timer to show how long it took you to win. That’s the first thing you’ll implement in this tutorial.

First, however, you’ll take a deeper look at Android Services.

Introducing Android Services

An Android Service is a component that helps execute long-running processes, like updating a database or server, running a countdown and playing audio. By default, Android Services run in the same process as the main application thread does. This kind of service is also known as a local service.

For resource-intensive tasks, the service executes the work on the background thread. This lets the user run actions without being disturbed. For example, if the user wants to make a call or check messages while updating a server, they can do so without interrupting or aborting the update action.

To do this, the developer needs to create a background thread and manually specify which tasks should run on it because the service doesn’t directly support the thread implementation.

Since an Android Service doesn’t have a user interface, it isn’t bound to the activity’s lifecycle. That means you can run it even when the user isn’t interacting with the app.

Additionally, other components can bind to the service and interact with it, or even do InterProcess Communication (IPC). You’ll learn more about IPC later in this tutorial.

In the following sections, you’ll implement each of the below types of Android Services in the Memo app to achieve the following features:

  • Foreground service: Add TimerService , which contains logic to track time.
  • Bound service: Implement MusicService , which will let you play, pause, stop and shuffle the audio tracks.

It’s time to get started!

Declaring a Service in the Manifest

Before using a service, you need to declare it in AndroidManifest.xml. After all, it’s an Android component, just like Activities are. For simplicity, the starter project already contains the Service classes, but you still need to configure them properly.

Navigate to AndroidManifest.xml and add this code inside application :

In this code, you see the following:

  • android:name: The name of the Service class.
  • android:enabled: When set to true allows the system to instantiate the services.
  • android:exported: When set to false tells the system that components of another application can’t start these services.

The value of android:name is in red, but just ignore that for now. You’ll fix this soon.

For now, you’ll start with the implementation.

Implementing the Service Interface

Every custom service class must be a subclass of Service and must implement and override a few basic callback methods connected to the service lifecycle.

The most important of these are:

  • onStartCommand(): Called by the system when another component wants to start a service using startService() . Once the system calls onStartCommand() , the service can run in the background for as long as it takes to complete. You need to remember to stop the service manually when the work is over by calling stopSelf() or stopService() . You don’t need this implementation if you only want to bind to the service without an option to start it.
  • onBind(): You always need to implement this callback method. The system invokes it when bindService() is called. Use it to bind another component to the service. It opens a communication, so you’ll provide an interface for the clients to communicate by returning IBinder . If you don’t want to use binding, just return null .
  • onCreate(): Use this method to set up a service before it starts. The system invokes it only if the service isn’t running yet.
  • onDestroy(): The system invoke this to destroy the service when it is not needed anymore. It’s the last call the service receives and it cleans up the resources or threads.

Creating a Foreground Service

A foreground service executes tasks that the user needs to see. It shows a status bar notification to alert the user that an app is performing an operation and consuming resources. The notification must have a priority of PRIORITY_LOW or higher and must be visible even when the user isn’t interacting with the app.

The user can’t dismiss the notification; it disappears when the service stops or leaves the foreground.

To see this in play, you’ll implement TimerService . Open TimerService.kt and add the following to make it a subclass of Service :

With this code, you implement the Service and CoroutineScope interface.

Implementing the Service Methods

Look closely and notice that Android Studio is showing an error because onBind() is missing.

To fix this, add the following methods to TimerService :

Here is a breakdown of the code:

  1. Since this is a foreground service, you don’t need binding so you return null instead of IBinder . Also note that you won’t implement onCreate() now since you don’t need any specific setup for the service.
  2. Here, you go through the Intent extras to get the value that the key SERVICE_COMMAND saves. This value indicates which action the service should execute.
  3. If the system kills the service because the memory runs out, START_NOT_STICKY tells the system not to recreate the service with an undefined Intent . Alternative constants are START_STICKY and START_REDELIVER_INTENT . If you’re interested in these, check out the official service constants documentation.
  4. Remove all Handler callbacks for the ticking time to keep the memory clean. Also, clean up the resources by canceling the whole timer Job since you’ll destroy the service in the next step.

Adding Permissions

All apps that target Android 9 (API level 28) or higher must request permission to use a foreground service. The system automatically grants that request because it’s a type of normal permission. Failure to do so leads the app to throw a SecurityException.

In Project view, navigate to app ▸ manifest ▸ AndroidManifest.xml and add the following code above the application tag:

This lets you run the foreground service in Memo.

Next, you’ll create a notification for the service.

Creating a Notification Channel

Every foreground service must notify the user that it has started. You also need to define a Notification Manager, which notifies the user of events that happen and holds information about one or more notifications.

Open NotificationHelper.kt and add this code at the top of the class:

Here, you’re lazy initializing notificationManager by getting the NOTIFICATION_SERVICE system service and casting it as NotificationManager .

In Android 8 and later, the notification must be part of a notification channel. To create one, add this code to NotificationHelper.kt:

In this code, you:

  1. Create a notification channel with CHANNEL_ID as its ID, CHANNEL_NAME as its name and the default importance.
  2. Set the notification channel’s description to CHANNEL_DESCRIPTION and sound to null which just means that there is no sound played when a notification is triggered in the channel.

The next step is to define a notification view.

Creating a Notification Builder

For the user to be aware of the service running, create a view that the user can see in the status bar. At the top of NotificationHelper.kt, add the notification code:

If you get an error saying contentIntent isn’t defined, don’t worry. You’ll take care of it in the next steps.

For now, in this code:

  1. You’re using NotificationCompat.Builder to create a status bar notification builder.
  2. The builder has to contain information about some of the notification’s options. However, you don’t have to define the notification options when you declare a builder. If you’re missing information about the title, sound and so on, you can set that information later, in the notification itself.
  3. This kind of notification should be set as auto-cancelable, which means that when the user clicks it, it’s automatically dismissed.

Building a Notification

Now, it’s time to build the notification itself. Add the following to NotificationHelper.kt:

Here’s what’s happening above:

  1. If the version of Android is equal to or greater than Android 8, the system creates a notification channel and returns Notification . Unfortunately, the Support Library for versions before Android 8 doesn’t provide notification channel APIs. Read more about this issue in the official notification channel documentation.
  2. Return a Notification after invoking build() on the builder.

Notification can be dynamically updated. In this case, you’ll update the text if the user closes the app while the service is running.

Below getNotification() , add the following:

Here’s what’s happening:

  1. You update the text in the notification published in the status bar via the notificationBuilder
  2. Then notify the Notification Manager about which notification to update. To do that, you use a unique NOTIFICATION_ID .

Finally, you’ll define what happens when a user clicks on the notification. Add this to the top of NotificationHelper.kt:

Here, you’re doing a lazy initialization of PendingIntent , which launches MainActivity when the user presses the notification.

Great job! You’ve done a lot of work already. Now, it’s time to actually run the foreground service.

Starting and Stopping the Service

To start the service in the foreground, use startForeground() . This method needs two parameters: the unique positive integer ID of the notification and Notificaton .

Open TimerService.kt and add the below to startTimer() method:

This method makes the service run in the foreground and posts the notification with the ID of NOTIFICATION_ID to the status bar. You’ll notice that helper is highlighted in red because you haven’t defined that variable yet.

To fix that, create an instance of NotificationHelper class at the top of TimerService :

To try starting the service from another component, open MainActivity.kt, find sendCommandToForegroundService() and add:

Here, you start the service from Activity. You pass its Context and the Intent to start the service.

Everything that starts must end, and that includes Service . Open TimerService.kt and add the following to stopService() :

In this code block:

  1. This call tells the system that it should remove this service from foreground state. The passed boolean argument corresponds to removing the notification when set to true
  2. Since a service can start itself, it must handle stopping itself, as well. stopSelf() handles that use case.

Updating the Notification When the Timer Changes

TimerService contains a coroutine that ticks every second while the level is running. You’ll use the timer value to update the notification view.

Look for broadcastUpdate() inside the TimerService.kt, and add this code inside the if :

Here is what this code block does:

  1. Here, you send a broadcast with the elapsed time to MainActivity . With it, MainActivity can update the time in the TextView below the card’s view.
  2. This helper method updates the status bar notification you posted above.

At this point, you’ve implemented everything the user sees while playing the game. But what happens if the user kills the app while the timer is running?

To handle that, add the following line to broadcastUpdate() in the else if :

This line updates the notification text to call the user back to the game.

Awesome work! Build and run to test the timer. Start a level and notice how the timer changes at the bottom. Pull down the status bar to see how the timer changes within the notification. Try exiting the application to test the message text update in the notification.

Using Background Processing for Complex Work

Sometimes, the user doesn’t need to know about certain actions happening, e.g. if you store the user’s activity on the server for developing purposes, you don’t have to display a notification. Place this kind of continuous work and similar in the background.

To achieve that, you can use:

  1. Custom Background Service – by default, the service runs on the UI thread. To avoid blocking it, create a Service with a job processing on the background thread.
  2. IntentService – a subclass of Service that executes requests sequentially by using worker thread. Since Android 8, it’s usage is not recommended. Also, IntentService is deprecated from Android 11.
  3. JobIntentService – a replacement for IntentService. Instead of service, it uses JobScheduler for executing jobs. In earlier versions than Android 8, it will act just like IntentService. For more info, read the official JobIntentService documentation.
  4. Background work with WorkManager – this is a general concept for doing background work in Android. Use it when you want to execute a periodical job in the future, or when you have some job constraints.

Explaining Background Execution Limits

Android 8 and newer versions have restrictions when using Android Services on the background thread:

  1. The system will destroy the service after some time if the app runs the service in the background. Once it goes to the background, it has a window of a few minutes in which it can interact with services. After that, the system kills all running services.
  2. The system will throw an exception if the service was started when the app is in the background and outside of the time window.

Now, it’s time to learn about the last kind of service.

Creating a Bound Service

A bound service is an implementation of Service . It’s a component that other components bind to, interacting with it and performing interprocess communication (IPC). The bound component can be an Activity, another service, a broadcast receiver or a content provider.

The lifecycle of the bound service depends on another application component. When the component unbinds, the bound service destroys itself. Consequently, it can’t run in the background forever.

However, it doesn’t necessarily need a bound component — it can start and stop itself as well. In that case, there’s an option to run indefinitely.

To try this out, you’ll give Memo the ability to play audio.

Converting MusicService into actual Service

To implement the audio playing feature, you’ll use MusicService . Firstly, modify it to have access to basic service methods.

Open MusicService.kt and make it extend Service :

As its type says, another component will use this service to bind to it. You already learned about the mandatory method you need for binding to service, so add it to MusicService :

The difference between the last implementation of onBind() and this one is, obviously, the return value. Since you’re binding to service here, you need to provide the IBinder value.

IBinder is a programming interface of Binder that clients use to interact with the service. Its methods allow you to send a call to an IBinder object and receive a call coming in to a Binder object. To learn more, check out IBinder’s documentation.

Android Studio shows an error because you haven’t defined binder variable. To fix this, add the following to the top of the class:

Here, you’re doing a lazy initialization of binder , which is a type of MusicBinder . Implementation of MusicBinder is your next step.

Defining a Binder

This service can’t be accessed outside of this application and doesn’t have its own process. Therefore, you have to create an interface that will have access to the service’s context. Do that by extending the Binder class. This way all components can use all public methods from Binder or the Service.

Now, to define the interface, add these lines at the bottom of the class:

MusicBinder is nested inside another class and it can access all methods from it. It can use all of Binder’s methods as well. Inside of it, you create a method for retrieving a service context.

Defining Service Methods for Managing Audio

This service allows the user to interact with the audio icons for playing, pausing, stopping and shuffling the music. For simplicity, the methods for managing audio are already defined. However, a music player isn’t.

To instantiate the music player, use this code inside initializeMediaPlayer() inside MusicService.kt:

Here, you use MediaPlayer to run a continuously repeating audio of the first song in randomSongs .

Another fun feature is that this bound service can provide the name of the track that’s playing. Inside MusicService , add:

In this method, you’re reading a track name from the resources and changing the result String to be more readable to the user.

All done! Now, you’ll use these methods from another component.

Creating a Service Connection Callback

To use MusicService inside other classes, you have to create its instance. Open MainActivity.kt and add the following at the top of the class:

Here, you’re declaring a service variable that holds a service instance. For now, the service is null. You’ll assign a new value when the activity connects to the service by using the Binder interface. To catch the connection state changes, create a connection callback.

Add the code below the musicService initialization:

That code is easy to digest:

  1. This is a callback for the service connection state.
  2. When activity connects to service, the system uses MusicBinder instance and getService() to give a reference to musicService .
  3. When service disconnects, the audio will stop if the service reference isn’t already null , clearing the service reference.

This sets a flag, isMusicServiceBound , that checks a service-bound state in both methods according to the parameter you provided. This is important to avoid DeadObjectException exceptions, which remote methods throw when the connection breaks.

Binding to the Service

Your next step is to bind the service when MainActivity starts. Find onStart() and add:

Here, you’re checking whether the service has a binding already. If not, you call a binding method.

The binding method doesn’t exist yet, so add its code below onDestroy() :

In this code, you:

  1. Declare an intent to start MusicService .
  2. Provide the Intent to the service along with the connection callback and a flag that automatically creates the service if the binding exists.

To avoid memory leaks or bugs, you need to add code to unbind the service. Add the following to unbindMusicService() :

With this, you tell the service to execute onServiceDisconnected() in the boundServiceConnection callback.

Using Service Methods

Once the service unbindes, you need to stop the music. Add the following code above the unbindService() line you just added:

Here, you use the service instance to stop the audio. Remember that you weren’t able to call methods from TimerService . Then, you needed to provide flags through Intent . However, here you have a connection — a binding — to the service, so you’re able to call its methods and receive a response.

To trigger an audio action, use sendCommandToBoundService() . Now, create a generic call for changing the action to reduce a number of code lines. Add this line to sendCommandToBoundService() :

With this, you tell the service to execute an action that matches the sendCommandToBoundService() parameter.

There is one more thing to do! Once the song starts to play, the service can provide info about the song’s name. Before you try that out, you need to fix the part with receiving a result.

Inside getNameOfSong() , replace the line which returns “Unknown” text with:

Here, you call a method from the service that checks which audio track is currently playing and returns an optional String result. If the result is null , you use a resource text instead.

Build and run, then press the Play icon to start the audio. Press GET SONG NAME to see the running song name in a Toast message. Finally, you can enjoy sound while playing your game!

Interprocess Communication

Every Android app runs in its own process with a unique process ID. When you start an app, the Android system generates a process and runs a main activity on the main thread. This has the advantage that the app lives in an isolated environment and other apps can’t interrupt it.

Based on this, Android allows you to run components in a different process that isn’t used to start an app. To do this, you need to use the process tag inside AndroidManifest.xml. The process can have a random name, like myNewProcess.

Multiprocessing gives your app better security and memory management. If you use it, however, you need to find a way to communicate between different processes.

You only need to include one programming interface — IBinder — but Android provides three ways of defining it:

You already implemented the first approach in this tutorial, but feel free to investigate the other two.

Where to Go From Here?

Download the final project using the Download Materials button at the top or bottom of this tutorial.

You’ve learned a lot of new things about Android Services and how to implement them in different ways. Services are useful for app optimization and improving the user experience.

Here are some links you can refer to:

Android 12 will bring some changes to foreground notifications. Check them out in the official foreground services documentation.

If you have any questions or comments, feel free to join the forum discussion below.

Источник

Читайте также:  Proxy для android без root прав
Оцените статью