Services Made Simple - Thanks to the Vapor Android Framework

The Vapor Android framework also provides an efficient model for the Services you write, by executing them inside their own separate thread.

Vapor handles the looping and management of this thread for you, making it possible to pause the service at any time using .paused(boolean), or have the underlying thread sleep for an arbitrary interval once per loop iteration using .sleepFor(int).

The documentation offers more detail on using Vapor Services, the purpose of this page is to give Android app developers a basic walkthrough on how to use VaporService with your own implementation.

Lifecycle Methods

The lifecycle events of a Service are similar to the standard Android Service lifecycle, but with some tweaks.

One confusing problem with the Android Services API is that after the initial bind event, no further bind events are raised for additional clients that bind to your service.

The Vapor Android framework remedies this by merging the .onRebind(Intent) and .onBind(Intent) events to give you one method: .bind(VaporIntent,boolean).

The Vapor Intent parameter is the Vapor framework equivalent to a standard Android Intent, and the boolean value will be true iff the event was raised from a rebind.

This helpfully means Android app developers will ALWAYS be notified whenever a client binds to a service!

As is often the case, developers shouldn't directly invoke lifecycle methods in their code. The Android framework uses this functionality at specific times in the life of your Service. Calling any of the Android lifecycle methods directly may result in Exceptions or unexpected behaviour.

create()

This is analogous to .onCreate() from the Android framework, and will be invoked in your code after Vapor has:

  • Set up the thread that the Service will executed inside
  • Created the Service Bindable framework that allows you to easily bind to, and unbind from, other Services

bind(VaporIntent,boolean)

This method unifies both .onBind(Intent) and .onRebind(Intent) events from the Android framework.

This is done to guarantee app developers can rely on a bind event always being raised when a client binds to your service. The boolean flag will be true if the event is the result of a rebind, and false otherwise.

Vapor will also take care of returning the IBinder instance to the Android framework on your behalf from .onBind(Intent). This will be an instance of VaporService.VaporBinder.

If you are using VaporService and VaporActivity classes in your project (we recommend you do!) then Vapor will also take care of managing this binding to your client (eg. an Activity). Both VaporService and VaporActivity implement VaporServiceBindable, and maintain a mapping of Services to VaporServiceConnections.

This means you can use .service(Class<T>) - where T extends Service - to obtain the instantiated VaporService instance of type T.

Similarly .binding(Class<T>) returns the VaporServiceConnection, a class which maintains additional information about the connection.

startCommand(VaporIntent,int,int)

This is analogous to .onStartCommand(Intent,int,int) from the Android framework, and by default returns the commonly used START_STICKY flag for the Service.

destroy()

This is analogous to .onDestroy(), and is invoked AFTER Vapor has stopped the Service. App developers should release resources and do any cleaning up, or necessary preservation of Service state here.

The Vapor Android framework will then:

  • Unbind any services left bound to the dying Service instance to avoid leaks
  • set several internal resources to null pointers for good housekeeping

runCode()

This method is probably the most important part of the VaporService API, therefore at the very least app developers need to implement this method in their VaporService.

The Vapor framework will fire this event once per iteration of the underlying thread loop, and it should therefore contain code that should be repeatedly executed whilst the service is running.

The Vapor framework will loop the underlying thread for you. Use methods such as .running(boolean), .sleepFor(int) and .paused(boolean) to alter the behaviour of this loop, as opposed to writing your own loop inside runCode()

Service Management Methods

bindable(boolean)

Use this method to set whether clients can bind to your service. Using .bindable(false) will mean that a null IBinder will be returned when a client attempts to bind to this service, which is treated by the Android framework as a signal that the service cannot be bound.

To query whether a service is currently bindable use .bindable() in your Android app. By default VaporServices are bindable.

priority(int)

Sets the requested OS priority of the underlying thread. Take care to only use Thread.MIN_PRIORITY, Thread.NORM_PRIORITY and Thread.MAX_PRIORITY as flags to avoid IllegalArgumentException.

To query the current priority use .priority(). The default value is Thread.NORM_PRIORITY.

sleepFor(int)

App developers should use this method to set how long you want the underlying thread to sleep for (in milliseconds) upon every iteration.

For example, your service might perform an operation that you only want executed once every minute:

        @Override
    	public void create() {
            // have the underlying thread sleep for a minute each iteration
            this.sleepFor(60000);
	    }

    

Moreover, you can change this interval dynamically inside .runCode(). For example, in periods where your service is having to deal with a spike in incoming data.

To query how long the underlying thread currently sleeps for upon every iteration use .sleepFor(). By default the thread sleeps for 0ms upon every iteration.

running(boolean)

Use this method to start the service with .running(true) in your Android app if it has not yet been started.

Likewise, developers can permanently stop a service using .running(false). As you can only stop a service ONCE you may want to use .paused(true) in order to suspend a service for an indeterminate period of time, as you can resume from this safely at any point in the future.

To query whether the Service is currently running use .running(). By default this method will return false until the service is explicitly started. Instead, you might actually want to use .state() as this will return a flag that takes in to account whether the service has been started, paused or stopped.

For example, state() == SERVICE_RUNNING will only be true if the service has been started, is not currently paused, and has not yet been stopped; whereas .running() does not take in to account whether the service is currently paused.

You can only call .running(false) once. Attempting to restart the Service thereafter will result in a ThreadStateException. To temporarily pause the Service arbitrarily use .paused(boolean) instead

paused(boolean)

Android developers should use this method to pause a Service for an indeterminate period of time arbitrarily. To pause a Service use .paused(true); this causes the Vapor framework to acquire a monitor on the underlying thread and safely tell it to wait until you call .paused(false) at some point in the future.

This means you can rely on efficiently being able to pause a Service in your code if you need to.

To query whether a Service is currently paused in your Android app use .paused(). By default .paused() returns false, as Services are not paused until instructed to be.

Instead, developers might actually want to use .state() as this will return a flag that takes in to account whether the Service has been started, paused or stopped.

For example, state() == SERVICE_PAUSED will only be true if the Service has been started, is currently paused, and has not yet been stopped; whereas .paused() does not take in to account if the Service has been started or stopped.

Binding To Other Services

See the VaporServiceBindable page for details on how to manage bindings to other Services in VaporService andVaporActivity instances.

$ Methods For Services

The $ class in the Vapor framework takes it lead from jQuery, as a powerful and convenient first port-of-call during development. In this context, the $ provides a lightweight way to start, and bind to services.

$.srv(Class<? extends Service>)

Conveniently, $.srv(Class<? extends Service>) is shorthand for the Android boilerplate code required to start a service using an application level context. The service will be started immediately, and the related ComponentName will be returned to the caller.

$.bind(...)

The $.bind(...) family of methods provides convenient ways for a client to bind to a bindable service. Consult the documentation for the various overloads and default parameters that can be used.

This method will only return true if the client has been successfully bound to the Service by the Vapor Android framework.

$.unbind(...)

The $.unbind(...) family of methods provides convenient ways for a client to unbind from a previously bound service.

Consult the documentation for the various overloads and default parameters that can be used.