Last week came the official announcement of the Android O release. This release of Android comes with some really cool new additions, and in this post I want to look specifically at the new restrictions that have been introduced for background services. If you’re using background services in your app then changes could affect your app, so let’s take a look at what these changes are and some alternative approaches we can take in our implementation.
There could be a bunch of reasons why our application is utilising background services — maybe it’s keeping our application data up-to-date with what’s on the server, maybe it’s shifting tasks to the background to unblock the UI or maybe we’re just carrying out some other long running task in the background. Whatever it is we’re doing, we’re going to be affected by these new changes in Android Oreo. But why has this change been introduced?
Well to begin with, Background Services are battery drainers — some applications can constantly be running services in the background (maybe to check your location for example), and this constant running of the service uses up a lot of battery on the device which isn’t really what you want for your users. But the main reason that this change was introduced was because background services can also adversely affect application performance — so if numerous applications are running processes in the background, then the application in the foreground may suffer in terms of performance due to the processes being carried out in the background.
I think these are two good enough reasons to make a change in this direction, ensuring that our users can gain a smoother experience in our applications whilst also ensuring their devices aren’t affecting at the same time.
So to put these changes into a nutshell, our applications no longer have the ability to freely run in the background — this means that if our application is either launched from an implicit broadcast, or if our application is launching services in the background, then these implementations will break with the introduction of Android Oreo.
Whilst this holds true for all applications that are targeting any version of Android— users on older versions of Android can still choose to opt-in to apply these restrictions within application settings, so even if we’re not targeting O yet then we still need to be proactive about these changes.
Service Restrictions
So the first component affected by these changes are Services. To begin with the most important thing to note is that if you attempt to call startService() when your application is not in the foreground then an IllegalStateException will be thrown. This means you can no longer use the startService() method when your app is not visible / being interacted with by the user. These change affects all services except those that:
Have been started when the application is currently in the foreground
If your application is still going to be calling startService() from the foreground, then when your application moves to the background there is a small amount of time that that your service is given before it is shutdown. Whilst this shows that this approach can still be used, it’s probably not something you should rely on — for example for services using the network, if the user is experiencing a slow connection and your task is taking longer to complete, if your app moves to the background then the service could be destroyed before your task has been completed (and the user possibly being unaware that the task didn’t complete). Because of this, be mindful of the tasks you are carrying out in these cases and don’t rely on the task being completed within this grace period.
When the service does reach the point where it is to be shut down by the system in this situation, then the service is stopped as if the stopSelf() method has been called.
To avoid running into any issues with these changes now in place, there are a number of different approaches that we can take. These include:
Scheduling jobs
So to begin with, using a Job Scheduler allows us to move away from our background service implementation and let the system take care of the execution for us. The system will also be intelligent with the jobs that we schedule, so scheduling multiple jobs means that they can be grouped and executed at the same time. We can also schedule jobs to run based on certain criteria, such as network connectivity and device power status — so not only does adapting to these changes avoid issues with the way things are now, but it also allows our application tasks to be run more efficiently.
You can check out the documentation for the Android Job Scheduler here. There is also the Firebase Job Dispatcher which allows you to achieve similar results when targeting API versions lower than Android 5.0.
Firebase Cloud Messaging and Service Whitelist
When it comes to services running in the background, there is a whitelist which is used to allow applications to temporarily run in the background as if they were running in the foreground. Applications will be included on this whitelist in situations when they are:
Being triggered from a high priority FCM/GCM notification
Performing SMS/MMS delivery
Acting from a Notification Action
So for example, in cases where we may need our application data to be refreshed based off of changes on the server, we can use FCM to send our application a notification that can trigger a service to fetch the latest set of data. For this, using High Priority messages allows our application to be added to a service whitelist which allows our services to run as if they were in the foreground. High Priority messages from FCM will be received immediately, even when the system is in the Doze state —and this is the point that the application will also be added to the temporary service whitelist. This means that we can start our service to update our application’s data as if our application was running in the foreground.
It’s important to note that this will only be the case for High Prioritymessages, other priority messages will be received when the device screen is turned back on or during the Doze maintenance window.
Starting a service in the foreground
In some cases, we may be running a service which is carrying out a task that the user may need to interact with or monitor the task that is being executed. Some examples of this could be when the user is downloading some new content in your app, using a timer to perform some time based operation, or maybe they’re receiving navigational directions from your application — these are all situations where the user needs to be aware of the task at hand.
For these kind of situations, we can run our service in the foreground — this is because when running, foreground services use a persistent notification to make the user aware that they are currently running.
Previously, we were able to start foreground services by simply calling startForeground() directly — using this method directly no longer works, so we need to make use of the new startForegroundService() method. The method itself is the same as calling startService(), but with the contract that startForeground() will be called. The difference with using this method as compared to startService() is that we can call it at anytime, even if our application is not currently in the foreground.
We can implement this by:
First using the startForegroundService() method, passing an intent for our service task to be carried out. This method will create our background service that we must immediately promote to the foreground.
Within this service we need to create a notification to be displayed for our foreground service. This must be of at least Low priority or higher so that is shown to the user on screen — if the priority is set to PRIORITY_MINthen the notification will not be displayed to the user.
Next, we can call startForeground(id, notification) from within the service — this will promote our service to the foreground.
Defer task to the foreground
If none of the above are appropriate solutions for your application, then another approach that can be taken is to simply defer the task to the foreground of the application. Personally I’d advise exploring the above solutions first as they will help you to avoid blocking your user interface and create a smoother experience for your user.
Broadcast Restrictions
The second set of changes that comes with Android Oreo are related to Broadcast Receivers. So essentially, any broadcast receivers that we have defined statically within our application manifest that are listening for implicit broadcasts will no longer receive those broadcasts.
The reason for this change is that implicit broadcasts would previously trigger any component that was listening for them within the manifest— this could have an adverse effect on application and device performance due to large numbers of applications registered to receive specific broadcasts all being triggered at the same time.
To avoid running into any issues with these changes now in place, there are a number of different approaches we can think about. These include:
To begin with, there is a ‘short’ list of exceptions when it comes to implicit broadcasts — this means that there are still some which you can register to receive broadcasts for. They are all listed below:
So if the broadcast that you have registered receivers for is on this list, then it will still function as it did previously (phew!). However, if the broadcast that you have registered to receive is not on this list then an alternative solution that we can take is to register a Job to be executed when certain broadcast events take place.
We touched on the JobScheduler slightly earlier, but with this API we have the ability to schedule jobs to be triggered intelligently when certain conditions are met, this could be in conditions such as:
When the device connectivity status changes, such as becoming connected to a network or more specifically a WiFi network
When the device has entered a power charging state
When there has been content provider changes
And finally, if our requirements are not satisfied by either of these solutions then we still have the ability to register broadcast receivers programmatically within our classes.
In this situation, we can simply use the registerReceiver() method call to register a dynamic broadcast receiver within our activity — followed by unregisterReciever() to ensure we unregister subscriptions based on the lifecycle of our activity. The only difference here is that we’re registering these listeners programatically and clearing up their subscriptions when our activity no longer needs them, rather than them being defined in our manifest to receive events just as they please.
So as you can see from this, if your application is currently using any of the approaches above, then you will need to shift some implementations to ensure that things don’t break for your users.
Whilst all of these changes are related to background tasks, things your user might not directly be aware of, it’s important to remember that these will have a positive effect whilst using applications by providing a smoother experience from a more efficient process flow for background tasks.
Like always, do drop me a tweet or leave a comment below if you have any questions or suggestions for these changes to background tasks
I’ve recently been working on a personal project and the past week has mostly been focused on design. I finally decided on a color scheme, downloaded some cool fonts, and made the app look a lot cleaner than the mess I had before. During this process, I noticed that the back button on my navigation bar didn’t look great — the standard Apple blue just didn’t mesh well with my design scheme. I knew it was possible to change that button but what was supposed to be a simple design fix turned into a harrowing journey. Let me just state: the way to do this is actually very simple, I just overcomplicated it. So I’m going to walk through how to do it and offer some tips along the way so you can avoid unnecessarily raising your blood pressure. Selecting Your Image What I thought was going to be the easiest part turned out to be the thing that tripped me up the most. I had found a button online that I liked but the color just wasn’t right. So I put it into Figma, changed the color, an...
A big problem that many developers face now a days is dealing with database. To have your app in app store in top list is not quite easy and to make the app ready for scalability is pretty hard. When our app is reached to many users, say a million, we have to care about everything in the app from performance to scalability. As far as I see till date developers have only two options “SQLite” and “Core Data”. Though both have a lot of advantages over each, I love to work with “Core Data” because of ease of dealing with records and persisting data and also due to the native advantages of “Core Data”. Very Recently I started using Realm that can be considered as a perfect replacement for “SQLite” and “Core Data”. What is Realm? Realm, it’s a cross platform mobile database for iOS and Android and designed specifically for mobile applications. It is available in both Swift and Objective-C. It is framed to be faster and better than SQLite and CoreData. With just f...
In Android, Chronometer is a class that implements a simple timer. Chronometer is a subclass of TextView . This class helps us to add a timer in our app. You can give Timer start time in the elapsedRealTime() timebase and it start counting from that. If we don’t give base time then it will use the time at which time we call start() method. By default a chronometer displays the current timer value in the form of MM:SS or H:MM:SS. We can set our own format into an arbitrary string. Chronometer code in XML : <Chronometer android:id = "@+id/simpleChronometer" android:layout_width = "wrap_content" android:layout_height = "wrap_content" /> Table Of Contents [ hide ] 1 Methods Of Chronometer In Android: 2 Attributes of Chronometer In Android: 3 Chronometer Example in Android Studio: Methods Of Chronometer In Android: Let’s discuss some important methods of chronometer that may be calle...
Introduction I have never been a fan of cross-platform, HTML based iOS and Android frameworks (PhoneGap, Cordova). They always seem to lag behind in features and responsiveness, and that’s a compromise I’m rarely willing to take. However, sometimes you can’t avoid embedding HTML and JavaScript into your project. In those situations, iOS uses the WKWebView component for loading and displaying web pages embedded within the application. WKWebView is based on Safari browser and uses webkit so it’s speed and responsiveness are on par with the latest and greatest of the mobile browser world. In this tutorial, I’ll show how to: Embed a WKWebView inside of your iOS Universal App Load an HTML webpage via URL Perform an action on the WKWebView html via JavaScript as a result of native controll action Respond to JavaScript events from your native application Access JavaScript variables from your native application Preparation ...
All views (including those that don't hold images) have a content mode that affects the way they draw their content. The default is Scale To Fill because it's fastest: the contents of the view just get stretched up (or down) to fit the space available. But there are two others that you'll be using a lot: Aspect Fit and Aspect Fill. "Aspect Fit" means "stretch this image up as large as it can go, but make sure that all the image is visible while keeping its original aspect ratio." This is useful when you want an image to be as large as possible without stretching its proportions, and it's probably the most commonly used content mode. "Aspect Fit" means "stretch this image up as large as it can go, cropping off any parts that don't fit while keeping its original aspect ratio." This is useful when you want an image to fill its image view, even when that means losing either the horizontal or vertical edges. If you want to f...
Method 1 In API level 11 or greater, use FLAG_ACTIVITY_CLEAR_TASK and FLAG_ACTIVITY_NEW_TASK flag on Intent to clear all the activity stack. Intent i = new Intent(OldActivity. this , NewActivity. class ); // set the new task and clear flags i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity(i); FLAG_ACTIVITY_NEW_TASK If set, this activity will become the start of a new task on this history stack. A task (from the activity that started it to the next task activity) defines an atomic group of activities that the user can move to. Tasks can be moved to the foreground and background; all of the activities inside of a particular task always remain in the same order. See Tasks and Back Stack for more information about tasks. This flag is generally used by activities that want to present a "launcher" style behavior: they give the user a list of separate things that can be done, which otherwise run comp...
’s been added to the JSVirtualMachine using addManagedReference:withOwner method and has not been removed using the removeManagedReference:withOwner method. Otherwise, the JSManagedValue gets set to nil, releasing the JSValue , and is free to be garbage-collected on the JavaScript side. JSExport A JSValue can represent and convert all of the JavaScript builtin types to Objective C/Swift and can convert them in the other direction to JavaScript types. However, a JSValue can’t convert Objective C/Swift classes to JavaScript objects without help. The JSExport protocol provides a way to convert Swift/Objective C classes and their underlying instance methods, class functions, and properties into JavaScript objects. By default when using JSValues , JavascriptCore will convert a Swift/Objective C class into JavaScript object but will not populate instance methods, class function...
Written by Reinder de Vries on May 3 2017 in App Development The Swift programming functions Map, Reduce and Filter can be challenging to wrap your head around. Especially, if you’ve always written for-loops to solve iteration problems! The Map, Reduce and Filter functions come from the realm of functional programming . In Swift, you can use Map, Reduce and Filter to loop over collection types like Array and Dictionary without using a for-loop. When building apps you typically use the procedural or object-oriented way of programming. Functional programming is different: it only deals with functions. No variables, no “states”, no for-loops – just functions. The Swift programming language lends itself perfectly for functional programming. You don’t need to strictly write functional code though, simply adopting concepts from functional programming (like Map, Reduce and Filter) can help you learn how to code ...
Extension functions are a really cool feature that Kotlin provides , and that you’ll find yourself using a lot when writing Android Apps. We have to admit that the Android Framework sometimes makes things a bit difficult , and in Java the only solution we have left is to create wrappers that do things like we want, or utility clases with static methods that are not the best in terms of readability. How would you like to be able to add extra functions to the Framework classes? This is what the Kotlin extension functions allow us to do. Extension functions in Kotlin Extension functions are functions that, as the name implies, help us to extend the functionality of classes without having to touch their code . Now let’s see how these functions are defined, and some examples that I personally find very useful. How can you define an extension function? Just write a function as you would normally, and put the name of the class before separated by a point. Th...
If you are familiar with Android apps development, you have dealt with components for sure (although maybe you don’t know them with that name) and specifically, with content providers . In this post, I am going to talk about how to use SQL injection to access data provided by this kind of components and how to be protected against this kind of attacks. But before, a bit of context to introduce the components of an Android app and content providers. What is a component in an Android app? An android app can contain several components with a specific aim and different lifecycle. These components, according to the official Android documentation, are entry points through which the system or a user can enter our app and help to define the general behaviour. The four components of an Android app are: Activities Services Content providers Broadcast receivers. Apart from the content providers, I am not going to explain in detail each component because I woul...
Comments
Post a Comment