Monday, February 29, 2016

DEB an Event Bus framework for Delphi

Hi all,
I have just started a new open source project: Delphi Event Bus a.k.a. DEB. As the title suggest DEB is an event bus framework based on publish/subscribe mechanism. It was inspired by EventBus framework for the Android platform.

How it works

DEB is designed to decouple different parts/layers of your application while still allowing them to communicate efficiently. The really exciting feature of this framework is that you can choose the delivery mode of the events: in the Main Thread or a Background thread.

Simply put the Subscribe attribute on your subscriber method you are able to receive a specific event, and by specifying the TThreadMode in attribute you can choose the context where to deliver the event.
For example, if you have to interact with the UI EventBus can deliver events in the main thread or If your subscriber does long running tasks (HTTP request), EventBus can also use background threads to avoid UI blocking. Regardless where an event was posted the EventBus will manage Thread synchronization, so you can deliver an Event in the MainThread and the subscriber will receive it on a background thread and viceversa.

Show me the code


  • DEB is a 100% ObjectPascal framework so it works on VCL and Firemonkey
  • It works with DelphiXE7 and major
  • It should be works fine also on AppMethod

Currently, the project consists in a simple getting started guide, 2 great samples and a suite of unit tests. There is a lot of work to do, so any contributor is welcome. The project is hosted on github and here there is the link. I hope you are excited as much as I am about this project!

Stay tuned!

Sunday, January 10, 2016

New Delphi Demos repository

Hi all,
I have created a new repository on GitHub to keep all interesting Delphi demo that I have figured out. Here the link to repository. This is also a way to share the code with you, so it can be improved. The first project pushed is LocationSensorPatch, relative to previous post. I will put all my demo ASAP.

Saturday, January 2, 2016

Using LocationSensor on Android Service in Delphi Seattle

Hi all,
this is a very great news!
Me and my CEO (Daniele Tetibit Time Professionals) have figured out how to implement and use the LocationSensor on Android Service.
Some months ago, I found out that there is a malfunction in Delphi: If you put LocationSensor component on Android Service DM, the service crashes. So I opened an issue on the quality portal, which was recognized and classified with majority prior.
However we need to retrieve the Device position from a background Service not by a foreground Activity.
We have investigated into the code and found this mistake in System.Android.Sensors unit:
  • For the majority of the code, it is assumed that the context of Application is an Activity 
Here is the code:

FActivity := TJNativeActivity.Wrap(System.DelphiActivity)^.clazz);

The code above works fine if you are in Android Activity context, like our case. If you are in a service context though, this doesn't work (the DelphiActivity pointer is null, rightly). If there is not necessity to have a reference to the Activty, but only the context of Application, this code is to be preferred:

LContext := TJContextWrapper.Wrap(System.JavaContext);

Below you can find the System.Sensors and System.Android.Sensors units (opportunely renamed System.SensorsDD and System.Android.SensorsDD), with the fixes explained earlier (the code contains comments for any changes):
// about line 748
  System.Variants, System.Math, System.Character,
  // -- patch dd
  // include the modified System.Android.SensorsDD

//about line 12
  // -- patch dd
  // use the modified System.SensorsDD
// about line 70
class constructor TPermission.Create;
  PackageInfo: JPackageInfo;
  PackageManager: JPackageManager;
  Activity: JActivity;
  LContext: JContext;
  // -- patch dd
  // Activity := TJNativeActivity.Wrap
  // (PANativeActivity(System.DelphiActivity)^.clazz)
  LContext := TJContextWrapper.Wrap(System.JavaContext);
  PackageManager := LContext.getPackageManager();
  PackageInfo := PackageManager.getPackageInfo
  FPermissions := PackageInfo.requestedPermissions;
// about line 100
  TAndroidGeocoder = class(TGeocoder)
  private type
    TGeocoderRunnable = class(TJavaLocal, JRunnable)
      FCoord: TLocationCoord2D;
      FLGeocoder: JGeocoder;
      constructor Create(ACoord: TLocationCoord2D; AGeocoder: JGeocoder);
      procedure run; cdecl;
  class var
    FGeocoder: JGeocoder;
    // FActivity: JActivity; // -- patch dd
    FActivity: JContextWrapper; // -- patch dd
// about line 130
  TUIAndroidLocationSensor = class(TCustomLocationSensor)
    FPermitted: Boolean;
    // FActivity: JNativeActivity; // -- patch dd
    FActivity: JContext; // -- patch dd
    FLastValue: JLocation;
    FLocationManager: JLocationManager;
    FAccuracy: TLocationAccuracy;
    FDistance: TLocationDistance;
// about line 1600
constructor TUIAndroidLocationSensor.Create(AManager: TSensorManager);
  LocationService: JObject;
  // FActivity := TJNativeActivity.Wrap
  // (PANativeActivity(System.DelphiActivity)^.clazz); // -- patch dd
  FActivity := TJContext.Wrap(System.JavaContext); // -- patch dd
  LocationService := FActivity.getSystemService
  if Assigned(LocationService) then
    FLocationManager := TJLocationManager.Wrap((LocationService as ILocalObject)
// about line 1630
  function RunIfPossible(var ARunnable: TLocationRunnable;
    var AListener: TLocationListener; AProviderName: JString): Boolean;
    Provider: JLocationProvider;
    LHandler: JHandler;
    Result := False;
    if FLocationManager.isProviderEnabled(AProviderName) then
      if AListener = nil then
        AListener := TLocationListener.Create(Self);
      Provider := FLocationManager.getProvider(AProviderName);
      if Provider <> nil then
        ARunnable := TLocationRunnable.Create(FLocationManager, AListener,
        // FActivity.runOnUiThread(ARunnable); // --patch dd
        // -- patch dd
        // You can use post method of Handler instead runOnUiThread in this case.
        // more info here:
        LHandler := TJHandler.JavaClass.init;;
        Result := True;
// about line 1830
class constructor TAndroidGeocoder.Create;
  // -- patch dd
  // FActivity := TJNativeActivity.Wrap
  // (PANativeActivity(System.DelphiActivity)^.clazz);
  FActivity := TJContextWrapper.Wrap(System.JavaContext);
  FGeocoder := TJGeocoder.JavaClass.init(FActivity);

Now you are able to using LocationSensor in this way:
  System.SensorsDD, System.Android.SensorsDD
  FSensors: TSensorArray;
  Sensor: TCustomSensor;
  TSensorManager.Current.Active := true;
  FSensors := TSensorManager.Current.GetSensorsByCategory(TSensorCategory.Location);

  FSensor := nil;
  for Sensor in FSensors do
    if TCustomLocationSensor(Sensor).SensorType = TLocationSensorType.GPS then
      FSensor := TCustomLocationSensor(Sensor);

  if not Assigned(FSensor) then
    Exit; { no location sensor is available }

  { start the sensor if it is not started }
  if not FSensor.Started then

You can find a complete demo here. Hopefully this solution will be helpful to you the way it was for us.

Stay tuned as because of this fix a very interesting application/project is about to see the light of day :)