Creating Android Services

From RAD Studio
Jump to: navigation, search

Go Up to Creating an Android App

An Android Service is an application without user interface that performs background tasks. There are essentially two types of services:

  • A started service: This service is started by an Android application. The service can run in the background indefinitely, even if the application is closed. This type of service usually performs a single task and automatically stops after finishing.
  • A bound service: This service only runs while it is bound to an Android application. There is an interaction between the application and the service, and it remains active until the application unbinds. More than one application can bind to the same service.

Creating an Android Service

RAD Studio provides a wizard to create Android Service projects, and another wizard to add Android services to a Multi-Device application.

To create a new Android Service project, choose File > New > Other, then navigate to:

  • Delphi Projects > Android Service

Use this wizard to specify the type of service, local or remote.

  • A local service is private to an application. Access from other applications is blocked adding a line to the Android Manifest file:
<service android:exported="false" android:name="com.embarcadero.services.<service_name>"/>
  • A remote service is public, and other applications can access it. Access to the service is granted adding a line to the Android Manifest file:
<service android:exported="true" android:name="com.embarcadero.services.<service_name>"/>

For more information about the different options, see Android Service.

For more information about the Android Manifest attributes, see Exported Provider Element.

Adding an Android Service to an Application

Once the service is created, it appears on the Project Manager as lib<project_name>.so:

  1. Add all the visual components to the data module, and the functions and procedures to the code.
  2. Save the Android Service project.
    Note1: Save each Android Service project in an exclusive folder.
    Note2: Do not name the Android Service project as Service.
  3. Build the Android Service project before adding it to the application in order to generate the binary files.
  4. Add to the Project Manager the application to which you want to add the service:
    1. For an existing application, on the project group, right-click and select Add Existing Project.
    2. For a new Multi-Device Application, on the project group, right-click and select Add New Project, then navigate to:
      • Delphi Projects > Multi-Device Application.
  5. On the Multi-Device Application, select the Android target platform.
    1. On the Android target platform, right-click and select Add Android Service.
    2. The Add New Android Service wizard appears.
    3. Click ProjectOptionsEllipsis.jpg to select the folder where your Android Service project is saved.
    4. Click Next.
      1. If everything is correct, then the files that are going to be added to your Multi-Device application appear listed.
      2. If an extra window appears requesting information about the Android Service paths, save and build the Android Service, then try it again.
  6. Click Finish to add the files to the application:
    • The main binary file, lib<project_name>.so. The binary file is added to the Deployment Manager.
      Note: This note does not affect RAD Studio Seattle Subscription Update 1. The local path to the lib<project_name>.so is absolute. If you move the service location to a different one, you need to add the service to the application again.
    • The libProxyAndroidService.so file. This library is added to the Deployment Manager.
      Note: This file is shared by all the services added to the application.
    • The Java archive, <project_name>.jar file. The jar file is added to the Libraries node on the Project Manager, under the Android target platform.
    • The data module file, <project_name>.pas file. The data module is added to the Project Manager.
  7. Compile the Multi-Device Application to generate the Android Manifest file, adding the line that corresponds to the type of service previously selected (local or remote). See Creating an Android Service.
    Note: Each service needs a corresponding <service> declaration in the AndroidManifest.xml. This is automatically added by the IDE.

Adding Several Android Services to an Application

You can add any number of services to an Android application.

Follow the steps on Adding an Android Service to an Application for each of the services to add.

Important things to take into account:

  • Save each Android Service project in an exclusive folder.
  • Name differently each project before adding it to the main application:
    • The Android Service project, lib<service_name>.so.
    Note: Do not name the Android Service project as Service.
    • The unit file.
    • The Data Module, by changing the Name property on the Object Inspector.

Deleting an Android Service from an Application

The process to delete an Android Service that is already added to an Android application, is manual:

  1. Remove the Java Archive:
  2. On the Project Manager, go to the Android target platform, then:

    1. Go to the Libraries node and select <service_name>.jar.
    2. Right-click and select Remove From Project.
    3. Click Yes on the modal dialog to confirm the operation.
  3. Remove the Data module:
  4. On the Project Manager:

    1. Go to the Service node and select <service_name>.pas.
    2. Right-click and select Remove From Project.
    3. Click Yes on the modal dialog to confirm the operation.
  5. Remove the binary files from the Deployment Manager:
    • lib<service_name>.so (specific to <service_name>).
    • libProxyAndroidService.so (shared by all the services).
      Note: Do not uncheck the libProxyAndroidService.so library if there are more services in the application. This is a file shared by all the services.

Note: The following does not affect RAD Studio Seattle Subscription Update 1.

AndroidServiceOutput type files cannot be deleted from the Deployment Manager.

To disable the files that are to be deployed to the target machine:

  • Select lib<service_name>.so and uncheck Chekbox.png.
  • Select libProxyAndroidService.so and uncheck Chekbox.png.
    Note: Do not uncheck the libProxyAndroidService.so library if there are more services in the application. This is a file shared by all the services.

You can also use the Revert to Default command button DMgrRevert.png to revert all changes that you have ever made in the Deployment Manager to the current project.

Note1: Do not use this option if you have more than one service added to the project and you do not want to remove all of them, or if you have other changes that you do not want to lose.
Note2: Remember to check the Keep added files option on the Revert to Default window to keep the files that you manually added to the project.

Starting a Service

Services can be started with ALocalServiceConnection.StartService('<service_name>') and ALocalServiceConnection.BindService('<service_name>'), or ARemoteServiceConnection.StartService('<service_name>') and ARemoteServiceConnection.BindService('<service_name>').

You initialize the TLocalServiceConnection variable to a specific service when starting or binding to it, after that you do not need to refer to the service name for the rest of methods.

Once you add an Android Service to your Multi-Device Application:

  1. Include the following unit in the Uses clause of the interface:
  2. Uses
      System.Android.Service; // Unit that contains the methods to work with services.
    
  3. Include the <service_name.pas> unit in the uses clause of the implementation. This allows you to use all the methos defined on the service data module.
  4. implementation
    
    uses
      MyLocalService; //Key sensitive
    
    {$R *.fmx}
    
  5. Construct a TLocalServiceConnetion variable for a local service, or a TRemoteServiceConnection variable for a remote service.
    1. Declare the TLocalServiceConnection/TRemoteServiceConnection variable:
      type
        TForm1 = class(TForm)
          ...
        private
          { Private declarations }
          FServiceConnection1: TLocalServiceConnection; // For a local service.
          FServiceConnection2: TRemoteServiceConnection; // For a remote service.
        public
          { Public declarations }
        end;
      
    2. Create the TLocalServiceConnection/TRemoteServiceConnection variable:
      FServiceConnection1 := TLocalServiceConnection.Create; // For a local service.
      FServiceConnection2 := TRemoteServiceConnection.Create; // For a remote service.
      

Started Service

For a Started service, call StartService('<service_name>') to start the service.

When using services as started, you need to manage the service process stopping the service with JavaService.stopSelf;.

Sticky Start

The OnStartCommand event for the service is defined by default as START_NOT_STICKY.

  • START_STICKY is used for services that are explicitly started and stopped as needed. The system tries to re-create the service when killed.
  • START_NOT_STICKY is used for services that should only remain running while processing any commands sent to them. If the process is killed, the service is not restarted automatically.

If you want to have a START_STICKY on the OnStartCommand event, you need to specify it on the service:

function TService1DM.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  Result := TJService.JavaClass.START_STICKY;
end;

For more information, see Service Lifecycle.

Bound Service

For a Bound Service, call BindService('<service_name>'), to bind to the service so that you can start interacting with it, and UnBindService to disconnect from the service.

For more information, see Bound Services.

BindService / UnBindService Methods

When the main application calls BindService('<service_name>'), the connection variable gets a pointer to the memory address where the service is running.

After stablishing the connection to a specific service, when you call UnBindService, and the application is the only one bound to the service, the service frees himself. Take into account that the connection variable of the main application remains pointing to the same memory address. Binding to the same service again can provoke a crash on the main application because the memory address to the service could be invalid.

There are two ways of handling this situation:

  • Avoiding ARC using the [UnSafe] attribute.
  • Assigning Nil to the variable before unbinding from the service.

Using the [Unsafe] Attribute

  private
    { Private declarations }
    [Unsafe] Service1: TAndroidService1DM;

For more information see The Unsafe Attribute.

OnBind Event

When you call BindService('<service_name>') on your application, the OnBind event triggers on the Android Service project. The OnBind method returns a IBinder object that is responsible of actually managing the connection with the service.

Overwriting the OnBind method causes that the event does not return the IBinder object that the main application needs to bring the Data Module from the service.

The following code is for advanced users that need to use the OnBind method:

  1. Include the following units in the Uses clause of the interface:
  2. uses
      Androidapi.Jni, Androidapi.JNIBridge;
    
  3. Create a function to get the IBinder object:
  4. function GetBinder(const AService: TAndroidBaseService): JIBinder;
    
      function GetmBinder(AJNIService: JNIObject): JIBinder;
      var
        Env: PJNIEnv;
        Clazz: JNIClass;
        FieldID: JNIFieldID;
        LJNIBinder: JNIObject;
      begin
        Result := nil;
        PJavaVM(System.JavaMachine)^.AttachCurrentThread(System.JavaMachine, @Env, nil);
        Clazz := Env^.GetObjectClass(Env, AJNIService);
        FieldID := Env^.GetFieldID(Env, Clazz, 'mBinder', 'Landroid/os/IBinder;');
        if FieldID <> nil then
        begin
          LJNIBinder := Env^.GetObjectField(Env, AJNIService, FieldID);
          if LJNIBinder <> nil then
          begin
            Result := TJIBinder.Wrap(LJNIBinder);
            Env^.DeleteLocalRef(Env, LJNIBinder);
          end;
        end;
        Env^.DeleteLocalRef(Env, Clazz);
      end;
    
    begin
      if AService.JavaService <> nil then
        Result := GetmBinder((AService.JavaService as ILocalObject).GetObjectID)
      else if AService.JavaIntentService <> nil then
        Result := GetmBinder((AService.JavaIntentService as ILocalObject).GetObjectID)
      else
        Result := nil;
    end;
    
  5. On the OnBind method return the IBinder object:
  6. function TAndroidServiceDM.AndroidServiceBind(const Sender: TObject;
      const AnIntent: JIntent): JIBinder;
    begin
      // .... User's code
      Result := GetBinder(Self);
    end;
    

Troubleshooting

Changing the Build Configuration Before Deploying

One of the files that constitute an Android Service in RAD Studio is the lib<service_name>.so. This library file is generated when you compile the Android Service, and it is saved to .\$(Platform)\$(Config) by default.

When you add the Android Service to the host application, the library file lib<service_name>.so is added to the selected build configuration in the Deployment Manager, for example, Debug. If you deploy the Android application selecting a different build configuration, for example Release, the needed file is not deployed because it is not automatically added to the Deployment Manager, which causes a run-time error.

In order to add the needed files to the correct build configuration, add the service to the main application again.

Adding the Release lib<service_name>.so

To include the Release lib<service_name>.so to the host application, instead of the Debug lib<service_name>.so:

  1. Clean the Android service project to remove other remaining lib<service_name>.so files.
  2. Compile the Android service project for the Release configuration.
  3. Add the Android service to the host application for the Release configuration, before deploying the application to the Android device.
    Note: Check in the Add Android Service wizard the file added.

Known Issues

If you encounter issues with Java Templates, see Android Services Presentations and Workarounds for information and resources.

See Also