Delphi XE5 + Android: first impressions

Back to the roots


I picked up the Delphi XE5 on the occasion of the Autumn Mobilization contest. I definitely liked the idea (and opportunity) to write for Android not on C-Sharp or Java, but on the familiar Pascal along and across Pascal. I’ll tell you here about my impressions, the problems that I met, as well as debunking some “urban legends”.

Used trial version of Update-1. Now, it seems like the second update has come out and, perhaps, something has changed. I’ll immediately notice that it’s better not to change the default settings in the installation. The Android-SDK installed before this could not be attached to Delphi, so it was reinstalled with the one that came with it. After the first launch, it turned out that Help does not work. Found a solution to
support.embarcadero.com/article/43035

Help was sensible and quite detailed. It contains not only properties and methods, but also examples and even a description of development methods. In general, a return to the roots, as Borland had it.

I really like the environment. In Visual Studio, everything is somehow amorphous and slurred. Unity is visually not bad, but there is a completely different specificity. In short - the programmer’s language still will not describe what the eye of an esthete sees, even if they belong to one person ...

User interface

FireMonkey pleased with its flexibility. On any control, you can hang another, on that one, and so on, achieving very interesting results. Compared to VCL, property naming is standardized. No more Captions and other things, if somewhere there is text - it is always Text. Position is always Position. A lot of ways to align. In addition, there is TLayout - something “immaterial” (more on that below), invisible, on which you can put controls and align them “in the void”, and not necessarily on some panel.

When there is a lot of things on the form, it becomes very useful property DesignVisible - to hide in design time. There was only one set of styles for Android, but very elegant - white on black, as I like.
There are rumors in the internet that references to the style for control (StyleLookup) are sometimes "not saved". For many types of controls (and maybe for everyone) there is a “default” link for each, which will be assigned even if not specified, and which is not saved, as I understand it, to save space in the form resource.

You can add control to the animation, and even several, and even at the same time. And this is not only moving around the screen, but also changing any material-numerical properties (sizes, colors, scale, etc.). For each animation, you can specify the time delay of its beginning, which is very convenient in difficult cases, because You can do without additional timers by simply running all the necessary animations at the same time from one block of code.

Now about gestures. In principle, everything is simple - we assign the Touch.GestureManager to the control, tick off the gestures of interest, tick off the boundaries for gestures (if the control is small) in the TouchTargetExpantion, create an OnGesture event for it and catch the desired gesture on EventInfo.GestureID. But there are subtleties.

For example, on a large TLayout, we placed some small controls (relative to it), and no matter how much the user “got” a finger on these controls with his gesture, something needs to be done there. I note - if everything described in the paragraph above is done for this TLayout, then we will catch only those gestures, the beginning of which falls on the "visible" objects - i.e. to one of those very small controls. I determined this experimentally. In principle, there is nothing surprising - the lightout is somehow not there, it is invisible and virtual, and all the "on-screen messages" that it can receive are from the "visible" objects placed on it. You can do it in another way - do not be lazy, appoint a manager and create an event for the form (as is done in the demos) and guaranteed to always receive it - but then you have to manually deal with the coordinates to determine

Also under Android, I would strongly recommend explicitly checking the GestureID of each caught gesture and reacting only to those that are of interest (regardless of which gestures are checked).

And an example. For a long time I could not figure out how to show the banner in TWebBrowser. Found a solution on one forum and creatively reworked. But, to be absolutely precise, not to the end. Practicing perfectionists can have fun and look for this defect. However, the code is absolutely working, and I use it:

procedure ShowHtml(WebBrowser: TWebBrowser; const Html: string);
{$IF DEFINED(ANDROID)}
const
  tempFile: string = '/sdcard/Download/temp.htm';
  filePrefix: string = 'file:/';
var
  StrList: TStringList;
  MemStrem: TMemoryStream;
begin
  with WebBrowser do
  try
    StrList := TStringList.Create;
    StrList.Text := Html;
    StrList.SaveToFile(tempFile);
    URL := '';
    Navigate(filePrefix + tempFile);
  finally
    DeleteFile(filePrefix + tempFile);
    StrList.Free;
  end;
{$ELSE}
begin
{$ENDIF}
end;

HTML here is the code for this banner itself.

Database


XE5 includes a set of components for universal access to databases - FireDAC. In principle, all the names of properties and methods are like other similar sets, so everything is clear here. I used it to communicate with SQLite. Everything is so simple and usual that I don’t even know what to tell. Besides, I don’t remember anything - at that time I was watching something on the media player, my hands did everything.

To feel the difference, those who wish can, after comparison, after FireDAC do something with a database from a program on the same Unity. Come on, Unity, she’s playable, out of the same Visual Studio. After that, you begin to understand where the bullets are whistling, and where the natives are delivering the cocktails ...

Well, for those who like to do everything with their own hands I will give a small example of how to populate the ListBox without Bindings:

procedure TSomeForm.FillList(aList: TListBox; BegDate, EndDate: TDateTime);
var
  aItem: TListBoxItem;
begin
  aList.Items.Clear;
  with SomeQuery do
  try
    ParamByName('beg_date').AsDateTime := BegDate;
    ParamByName('end_date').AsDateTime := EndDate;
    Open;
    while not EOF do
    begin
      aItem := TListBoxItem.Create(aList);
      aItem.StyleLookup := 'listboxitemrightdetail';
      aItem.Tag := FieldByName('id').AsInteger;
      aItem.Text := Format('%s (%s) "%s"',
        [FieldByName('theme').AsString,
        FieldByName('name').AsString,
        FieldByName('question').AsString]);
      case FieldByName('d_result').AsInteger of
        -1: aItem.ItemData.Bitmap.Assign(NoImage.Bitmap);
         0: aItem.ItemData.Bitmap.Assign(WaitImage.Bitmap);
         1: aItem.ItemData.Bitmap.Assign(YesImage.Bitmap);
      end;
      aItem.ItemData.Detail := FormatDateTime('dd-mmm-yy', FieldByName('d_date').AsDateTime);
      aItem.ItemData.Accessory := TListBoxItemData.TAccessory.aMore;
      aList.AddObject(aItem);
      Next;
    end;
  finally
    Close;
  end;
end;


Among other things, depending on the code in the d_result column, this or that picture is placed in the line of the sheet box:

aItem.ItemData.Bitmap.Assign

The main thing to remember is aList.AddObject (aItem);

Well, and Next, of course, so that it does not hang.

Manipulation with forms


What Delphi teaches is its own form for every action. Under Android, in it you can create, show and close forms in exactly the same way as under Windows. Each new one way or another created and shown form will be as if “modal”, i.e. covering all application space. However, Form.ShowModal should not be done (Android doesn’t understand this), but in the old fashion, just call Form.Show. Using the Back system button, Form.Close is automatically called and the top-most current form is closed. You can then use it again. When you close the main (first) form, the application, as you would expect, closes. I note that you should not close the form with the caFree parameter or explicitly destroy it (Free, Release) - Android does not like this!

Reference counting.

I read on the internet about problems with people with ARC. I’m sure that’s not the point. If everything is correctly designed, then it doesn’t matter at all whether links are counted or not, a garbage collector with a scythe runs there as scheduled in .Net or is destroyed immediately like in Delphi. I wrote everything the old fashioned way:

try
  Create;
finally
  Free;
end


and worked like a clock under both Android and Windows.

If there are any problems with understanding this process, I recommend a little pee on a s-sharpe without any banter. There, in general, destructors are not explicitly called, just either exit the procedure where the given object was a local variable, or set the (global) variable to null. After a while, with your spinal cord, you begin to feel the moment when the rooks with objects go to Valhalla, and without any push from you.

Arrays


When developing for a mobile compiler, the code adaptation guide says “do not use static arrays”. One exception is also indicated - when a static array is a member of a structure. And that’s it. It is not clear whether this applies to array constants. For example, such as

Const
SomeNames: array [0..1] of string = (‘First’, ‘Last’);


It is possible that this can be done, although I tried to avoid this and formed arrays of strings in initialization dynamically. In C-sharpe there, even though this can be done in the description ... In short, the question requires further investigation and clarification.
It should also be remembered that the elements of a string in a mobile compiler are numbered from scratch.

Operators


A new operator has appeared (I don’t know in which version)

for item in container do

It seems that all languages ​​are striving for a common denominator. By the way, it is possible to sort through them in pascal not only arrays, but also sets.

Questions and valuable comments are welcome.

Also popular now: