Delphi's Android program is the native program, which is nativeactivity. Then you need to look at the principle of nativeactivity, in the Androidmanifest.xml file to specify the entry activity for nativeactivity, so that the application starts, the Java virtual machine this side open a main thread, The main thread creates an activity, which is nativeactivity, which, in the process of creation, goes to the application's. So dynamic link library to look for a function: __anativeactivity_oncreate ( Anativeactivity, void* size_t), and then call this function, this function is the real entry function in C + + code, in this entry function to write something, please refer to the NDK inside the native_app_glue. It is implemented in this way: for this incoming anativeactivity, the various events that set this activity are callback functions: Activity->callbacks->ondestroy = OnDestroy;
Activity->callbacks->onstart = OnStart; After Setup is finished, call:
Activity->instance = android_app_create (activity, savedstate, savedstatesize); This is implemented in Delphi's Androidapi.appglue unit, which is a simple package for the Android NDK under Delphi. Delphi in this unit in the export of a anativeactivity_oncreate is the previous introduction of the __anativeactivity_oncreate, this function is equivalent to the Delphi Android run the entry function of the program, In this function, Delphi saves a delphiactivity, which is used to save the activity structure. Android's entry location is no longer the code between the Delphi engineering file location's begin end. This function is packaged into the lib+ project name. So file, and then as a ubiquitous function, the program runs when it loads the so dynamic library and then loads the Anativeactivity_oncreate to execute the Android portal. This procedure calls Android_app_create, also in the Androidapi.appglue cell. This code is as follows:
--------------------------------------------------------------------//Native activity interaction (called from Main thread)//--------------------------------------------------------------------function Android_app_create ( activity:panativeactivity; Savedstate:pointer; savedstatesize:size_t): Pandroid_app;varandroid_app:pandroid_app; Pipedescriptors:tpipedescriptors;attr:pthread_attr_t;thread:pthread_t;beginandroid_app: = Pandroid_app (__malloc ( SizeOf (Tandroid_app)); Fillchar (android_app^, SizeOf (Tandroid_app), 0); Android_app^.activity: = activity; Pthread_mutex_init (Android_app^.mutex, nil);p Thread_cond_init (Android_app^.cond, nil); if savedstate <> nil Thenbeginandroid_app^.savedstate: = __malloc (savedstatesize); Android_app^.savedstatesize: = SavedStateSize; Move (pbyte (savedstate) ^, pbyte (android_app^.savedstate) ^, savedstatesize); end; Pipe (pipedescriptors); Android_app^.msgread: = Pipedescriptors.readdes;android_app^.msgwrite: = Pipedescriptors.writedes; Pthread_attr_iniT (attr);p thread_attr_setdetachstate (attr, pthread_create_detached);p thread_create (thread, attr, @android_app_ Entry, Android_app); Pthread_mutex_lock (Android_app^.mutex); while android_app^.running = 0 dopthread_cond_wait (android_app^.cond, Android_app^.mutex);p Thread_mutex_unlock (Android_app^.mutex); Result: = Android_app;end;
Visible in front and annotated, wrote native activity interaction (called from main thread), indicating that this is the main thread called. The program first creates a ANDROID_APP structure and then sets the activity of the app. Pthread_mutex_init (Android_app^.mutex, nil);//Create a thread synchronization object mutex mutex, Pthread_cond_init (Android_app^.cond, nil);// Creates an object for a thread communication. Used for the main thread (UI thread) and our threading communication. Then check to see if the Android system has saved the state for our app before. Some words can be restored directly to the good. It is also important to change the screen orientation of the Android application, and the activity will be re-established!!!!! Then create two pipe objects, one for the thread to read the message, one to write the message to pipe (pipedescriptors); Android_app^.msgread := pipedescriptors.readdes; Read message Android_app^.msgwrite: = Pipedescriptors.writedes; Write and then create the thread, run the program code pthread_attr_init (attr);p thread_attr_setdetachstate (attr, pthread_create_detached);p Thread_ Create (thread, attr, @android_app_entry, Android_app);//creating thread, thread entry is android_app_entry, entry parameter is android_app// Start waiting for thread to run up Pthread_mutex_lock (Android_app^.mutex); while android_app^.running = 0 do Pthread_cond_ Wait (Android_app^.cond, Android_app^.mutex); Pthread_mutex_unlock (Android_app^.mutex); return to Android_ after running App structure, which is equivalent to the oncreate of our activity. Then look at anThis thread entry function for Droid_app_entry
function Android_app_entry (param:pointer): Pointer; Cdecl Delphi:init system unit and rtl.procedure systementry;typetmainfunction = Procedure;vardlsympointer:pointer; Entrypoint:tmainfunction;begindlsympointer: = Dlsym (Rtld_default, ' _nativemain '); if Dlsympointer <> nil Thenbeginentrypoint: = Tmainfunction (Dlsympointer); Entrypoint;end;end; Varandroid_app:pandroid_app;looper:palooper;beginandroid_app: = Pandroid_app (param); Android_app^.config: = aconfiguration_new;//Create the Application Configaconfiguration_fromassetmanager (Android_app^.config, android_app^.activity^. Assetmanager); Get message from main thread with android_app^.cmdpollsource.id: = Looper_id_main;android_app^.cmdpollsource.app: = android_app;android_ App^.cmdpollsource.process: = @process_cmd;//Set the function of the command handling cmd android_app^.inputpollsource.id: = Looper_id_input; Android_app^.inputpollsource.app: = android_app;android_app^.inputpollsource.process: = @process_input;//function for input event handling Create a looper message loop to crawl the message looper: = Alooper_prepare (alooper_prepare_allow_noN_callbacks); ALOOPER_ADDFD (Looper, Android_app^.msgread, Looper_id_main, Alooper_event_input, nil, @android_app ^.cmdpollsource); Android_app^.looper: = Looper; Pthread_mutex_lock (Android_app^.mutex); android_app^.running: = 1; Setting that allows a thread to exit from waiting to open, that is, to exit Pthread_cond_broadcast (Android_app^.cond) from Android_app_create;p Thread_mutex_unlock ( Android_app^.mutex); {Delphi:this would initialize System and any RTL related functions, call Unit initialization sections and Thenproject Mai n code, which would enter application main loop. This call would block until the loop ends, which istypically signalled by android_app^.destroyrequested. }systementry;//Here is the code that calls the begin end of the project file, which is an encapsulation of Delphi, in fact, the Android_main (Android_app) is called in Android native; And then do some processing of the message here, waiting for the program to run the end {This place would is ideal to the call unit finalization, class destructors and so on.} Halt; Android_app_destroy (Android_app);//Destroy Android_app exit thread. This is actually the end Result of the android program: = Nil;end;
Then the
function Android_app_read_cmd (Android_app:pandroid_app): Shortint; Cdecl;varcmd:shortint;beginresult: = -1;if __read (android_app^.msgread, @cmd, sizeof (cmd)) = sizeof (cmd) thenbegincase CMD ofapp_cmd_save_state:free_saved_state (Android_app);//Release the current save state end; Result: = Cmd;end;end; Procedure Android_app_pre_exec_cmd (Android_app:pandroid_app; cmd:shortint); Cdecl Prepare to execute command State begincase cmd Ofapp_cmd_input_changed:beginpthread_mutex_lock (android_app^.mutex), if android_app^. Inputqueue <> Nil Thenainputqueue_detachlooper (android_app^.inputqueue); Android_app^.inputqueue: = Android_ App^.pendinginputqueue;if android_app^.inputqueue <> Nil thenainputqueue_attachlooper (android_app^. Inputqueue, Android_app^.looper, Looper_id_input, nil, @android_app ^.inputpollsource);p thread_cond_broadcast ( Android_app^.cond);p Thread_mutex_unlock (Android_app^.mutex); end; App_cmd_init_window:beginpthread_mutex_lock (Android_app^.mutex); Android_app^.window: = android_app^. Pendingwindow;pthread_cond_broadcasT (Android_app^.cond);p thread_mutex_unlock (Android_app^.mutex); end; App_cmd_term_window:pthread_cond_broadcast (Android_app^.cond); App_cmd_resume, App_cmd_start, App_cmd_pause, App_cmd_stop:beginpthread_mutex_lock (Android_app^.mutex); android_ App^.activitystate: = Cmd;pthread_cond_broadcast (Android_app^.cond);p thread_mutex_unlock (Android_app^.mutex); end ; App_cmd_config_changed:aconfiguration_fromassetmanager (Android_app^.config, Android_app^.activity^.assetmanager ); app_cmd_destroy:android_app^.destroyrequested: = 1;end;end; Procedure Android_app_post_exec_cmd (Android_app:pandroid_app; cmd:shortint); Cdecl;begincase cmd Ofapp_cmd_term_window:beginpthread_mutex_lock (Android_app^.mutex); Android_app^.window: = nil; Pthread_cond_broadcast (Android_app^.cond);p thread_mutex_unlock (Android_app^.mutex); end; App_cmd_save_state:beginpthread_mutex_lock (Android_app^.mutex); android_app^.statesaved: = 1;pthread_cond_ Broadcast (Android_app^.cond);p thread_mutex_unlock (Android_app^.mutex); end; App_cmd_resume:{Delphi:it is unclear so this is necessary in original Appglue, but It prevents Firemonkey Applicationsfrom re Covering saved state. Firemonkey recovers saved state usually after App_cmd_init_window, which Happensmuch later after Cmd_resume. } {free_saved_state (Android_app)};end;end; Procedure Process_cmd (App:pandroid_app; source:pandroid_poll_source); Cdecl;varcmd:shortint;begincmd: = Android_app_read_cmd (app);//First read command Android_app_pre_exec_cmd (app, cmd);//Prepare command IF Assigned (App^.onappcmd) then//program internal Instructions processing app^.onappcmd (app, cmd); Android_app_post_exec_cmd (app, cmd);//execute processing end;
The code will process the call in the Android message loop
In fact, there are many places in this code that are annotated. Take a closer look and you'll understand.
Then the program enters the project file's begin end, enters the Sysinit.pas unit's _initexe first, then calls Getthismodulehandle, which calls Dlopen (Info.dli_fname, Rtld_lazy) is equivalent to loading Windows DLL, will be loaded (lib+ program name. So) to get the current handle, and then Dlclose Close, and finally the program with the library handle of the project as a program hinstance, that is, we have a lot of resources should be packaged into this so, Finally, if it's an Android environment, it calls _startexe to start the program, and _startexe calls Initunits to initialize some cells, which invokes the contents of the initialization of each cell referenced by the program. In this process will initialize fmx.platform this cross-platform unit Tplatformservices class library, the library is cross-platform unit service management, and then will call Fmx.platform under the initialization, inside the Registercoreplatform Services will determine which platform to invoke on the registercoreplatformservices based on the chosen platform, which is determined by compiling the pre-processing instructions under Implemention
uses{$IFDEF ios} FMX. platform.ios,{$ELSE} {$IFDEF macos} FMX. platform.mac,{$ENDIF macos}{$ENDIF ios}{$IFDEF mswindows} FMX. platform.win,{$ENDIF} {$IFDEF android} FMX. platform.android,{$ENDIF}, under Android, the Registercoreplatformservice in FMX.PlatForm.Android is called to register the core platform service, and then there is the IF Assigned (Platformandroid.fandroidapp) then begin Platformandroid.fandroidapp^.onappcmd: = @ handleandroidcmd; Platformandroid.fandroidapp^.oninputevent: = @HandleAndroidInputEvent; end; This moves the previously mentioned Android message and input events to the Handleandroidcmd and handleandroidinputevent functions of the FMX platform and then handleapplicationevent and the message manager Tmessagemanag ER combines the processing of messages. After some of the initialization process in these units is done, the code is executed between the begin end in the project file, and the Application.Run is executed; then we look at the code that executes.
Procedure tapplication.run;varappservice:ifmxapplicationservice;begin{$IFNDEF Android}addexitproc ( Doneapplication); {$ENDIF} Frunning: = True;tryif TPlatformServices.Current.SupportsPlatformService (ifmxapplicationservice, Appservice) Thenappservice.run;finallyfrunning: = False;end;end;
In fact, he is the service platform that obtains the current running program through cross-platform service. That is, tplatformandroid in FMX.PlatForm.Android, this class inherits Ifmxapplicationservice, and has been registered by Registercoreplatformservices in the previous Tplatforman Droid, so this is actually called the tplatformandroid run process, which is actually starting to run the Android message loop processing. The code is very short, which is actually called Internalprocessmessages for internal message loop processing
Procedure tplatformandroid.run;begin{Although calling this routine isn't really necessary, but it's a to ensure tha T "Androidapi.AppGlue.pas" iskept in uses list, with order to export Anativeactivity_oncreate callback. }app_dummy; Repeatinternalprocessmessages;until fandroidapp^.destroyrequested <> 0;end;
First, there are eventpollvalue in the internalprocessmessages: = Alooper_pollall (getandupdatetimeout, nil, nil, ppointer (@ Peventpollsource)); Get the message through this first, if you get it there will be if (Peventpollsource <> nil) and Assigned (peventpollsource^.process) then begin peventpollsource^.process (Fandroidapp, Peventpollsource); If Eventpollvalue = Looper_id_main then hasevents: = true; Endpeventpollsou Rce^.process (Fandroidapp, Peventpollsource); This will invoke the Process_cmd or process_input that was previously set to initialize to associate the message with the actual. As for displaying the Android interface, The TWindowManager.Current.RenderIfNeeds will determine whether the interface information needs to be rendered, if necessary, call Twindowmanager.render to render the interface, and the final render Function procedure rendernormalwindows; var i:integer; paintcontrol:ipaintcontrol; begin & nbsp For I: = fwindows.count-1 downto 0 do if fwindows[i]. Form.visible and (not fwindows[i]. requirescomposition) and Supports (Fwindows[i]. form, IpaintcontRol, Paintcontrol) then begin paintcontrol.paintrects ([trectf.create (0, 0 , Fcontentrect.width, Fcontentrect.height)]); break; end; end; Paintrects This then begins to match the Fmxform paintrects function to draw the interface information. So an Android program turns on run to show basic finish. http://blog.csdn.net/suiyunonghen/article/details/45365529
Delphi Android Program startup process