📜 ⬆️ ⬇️

Delphi XE5 + Android: First Impressions

Back to the roots


I picked up Delphi XE5 on the occasion of the Autumn Mobilization contest. The idea (and the opportunity) to write for Android not on C-Sharpe or Java, but on a familiar length and width across pascal I definitely liked. I'll tell you here about my impressions, the problems that have met, and also I will debunk some of the “urban legends”.

Used trial version of Update-1. Now, like the second update came out and, perhaps, something has changed. Immediately, I note that it’s better not to change the default settings. The previously installed Android-SDK could not be attached to Delphi, so I re-installed it with the one attached to it. After the first launch, it turned out that Help was not working. Found a solution
support.embarcadero.com/article/43035

Help turned out to be sensible and quite detailed. Contains not only properties and methods, but also examples and even the description of development methods. In general, a return to basics, as it was still at Borland.

I like the environment very much. In Visual Studio, everything is somehow amorphous and unintelligible. Unity is visually not bad, but there is a completely different specificity. In short, the programmer’s language still does not describe what the esthete’s eye 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 more, and so on, achieving very interesting results. Compared with VCL, property naming is standardized. No more Captions and other things, if there is text somewhere - it is always Text. Position - always Position. Lots of alignment methods. In addition, there is a TLayout - something “immaterial” (about this will be below), invisible, on which you can put controls and align them “in the void”, and not necessarily on any panel.

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

It is possible to add animation to the control, 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 (size, color, 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 simultaneously from one block of code.

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

For example, on a large TLayout, we placed some small (relative to it) controls and no matter how “hit” the user is with a finger on these controls, we need to do something there. I note that if everything described in the paragraph above is done for this TLayout, then we will catch only those gestures that start with “visible” objects — that is, on one of those very small controls. This I determined experimentally. In principle, there is nothing surprising - as if there is no Layout, it is invisible and virtual, and all the “screen messages” that he can receive are from the “visible” objects put on him. You can do it differently - do not be lazy, assign a manager and create an event for the form (as is done in the demos) and always receive it guaranteed - but then you have to manually deal with the coordinates to determine which control relates to which gesture.

Also, under Android, I would strongly recommend explicitly checking the GestureID of each captured gesture and respond only to those that are of interest (no matter which gestures are marked with a check mark).

And an example. Long could not figure out how to show the banner in TWebBrowser. I found the solution on one forum and creatively reworked it. But, to be perfectly accurate, not to the end. Practitioners perfectionists can have fun and look for this shortcoming. However, the code is absolutely working and it is I who 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 is the code for this banner itself.

Database


XE5 includes a set of components for universal database access - FireDAC. In principle, all the names of properties and methods are similar to other similar sets, so everything is clear. I used it to communicate with SQLite. Everything is so simple and usual that I do not 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 themselves.

To feel the difference, those who wish can compare something after the FireDAC with the database from the program on the same Unity. Come on, Unity, she's a game, out of the same Visual Studio. After that, you begin to understand where the bullets whistle, and where the natives spread the cocktails ...

Well, for those who like to do everything with their own hands, I’ll give a small example of how to fill 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, one or another picture is placed in the box-box line:

aItem.ItemData.Bitmap.Assign

The most important thing to remember here is aList.AddObject (aItem);

Well, Next, of course, so as not to hang.

Form manipulation


What Delfi teaches is to take action in every form. Under Android, you can create, show and close forms in the same way as under Windows. Each new one created or shown in one way or another will be as if “modal”, i.e. closing the entire application space. However, Form.ShowModal should not be done (Android doesn’t understand this), but in the old way you should simply call Form.Show. Using the system button Back, the Form.Close is automatically called and the highest form at the moment is closed. You can then use it again. When closing the main (first) form of the application, as expected, closes. I note that you should not close the form with the caFree parameter or explicitly destroy it (Free, Release) - it does not like Android!

Reference counting

I read in the internet about the problems of people with ARC. I am sure this is not the case. If everything is properly designed, then it makes no difference whether the links are considered or not; a garbage collector with a scythe goes on schedule as in .Net or is destroyed immediately as in Delphi. I wrote everything in the old manner:

 try Create; finally Free; end 


And it worked like a clock and under Android, and under Windows.

If there are any problems with the understanding of this process, without any banishment I recommend a little pee on C-Sharpe. There, it is generally not customary to explicitly call destructors, either simply exit the procedure where this object was a local variable, or assign a (global) variable to null. After a while, the spinal cord begins to feel the moment when the rooks with the objects are sent to Valallla, and without any push from your side.

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 all. It is not entirely clear whether this applies to constant arrays. 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 the B-Sharpe there even though it can be done in the description ... In short, the question requires further research and clarification.
It should also be remembered that the elements of a string (string) in the mobile compiler are numbered from zero.

Operators


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

 for item in container do 

It seems that all languages ​​tend to 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.

Source: https://habr.com/ru/post/206754/


All Articles