Delphi的Android程序是原生的程序,也就是NativeActivity。那么就需要先看一下NativeActivity的原理,
在AndroidManifest.xml文件里面指定入口activity为nativeactivity,这样应用程序一启动,java虚拟机这边就开一个主线程,主线程创建一个活动,就是nativeactivity,这个nativeactivity在创建的过程中就会去应用程序的.so动态链接库中寻找一个函数:
__ANativeActivity_onCreate(ANativeActivity, void* size_t),然后调用这个函数,这个函数就是C++代码中的真正的入口函数,在这个入口函数里面
做写什么事情呢,请参考ndk里面的Native_app_glue。它是这样来实现的:对这个传进来的ANativeActivity, 设置这个activity的各种是事件的回调函数:
activity->callbacks->onDestroy = onDestroy;
activity->callbacks->onStart = onStart;
设置完了之后就调用:
activity->instance = android_app_create(activity, savedState, savedStateSize);
这个在Delphi的Androidapi.AppGlue单元中实现,这个就是Delphi下的Android NDK一些对应的简单封装。Delphi中在这个单元中导出了一个ANativeActivity_onCreate就是前面介绍的__ANativeActivity_onCreate,这个函数就相当于是Delphi的Android运行程序的入口函数,在这个函数中Delphi保存了一个DelphiActivity,用来保存这个Activity结构。Android的入口位置不再是Delphi的工程文件位置的Begin  end之间的代码。这个函数被打包到Lib+工程名.So文件中,然后作为一个到处函数,程序运行的时候会加载这个So动态库,然后加载ANativeActivity_onCreate执行Android入口。此过程调用android_app_create,同样在Androidapi.AppGlue单元中。这个代码如下:
// --------------------------------------------------------------------
// Native activity interaction (called from main thread)
// -------------------------------------------------------------------- function android_app_create(activity: PANativeActivity; savedState: Pointer; savedStateSize: size_t): Pandroid_app;
var
android_app: Pandroid_app;
PipeDescriptors: TPipeDescriptors;
attr: pthread_attr_t;
thread: pthread_t;
begin
android_app := Pandroid_app(__malloc(SizeOf(TAndroid_app)));
FillChar(android_app^, SizeOf(TAndroid_app), );
android_app^.activity := activity; pthread_mutex_init(android_app^.mutex, nil);
pthread_cond_init(android_app^.cond, nil);
if savedState <> nil then
begin
android_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);
pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
pthread_create(thread, attr, @android_app_entry, android_app); pthread_mutex_lock(android_app^.mutex);
while android_app^.running = do
pthread_cond_wait(android_app^.cond, android_app^.mutex);
pthread_mutex_unlock(android_app^.mutex); Result := android_app;
end;
可见在前面又注释,写了Native activity interaction (called from main thread),说明这个是主线程调用的。程序首先先创建了一个android_app结构体,然后设置 app的activity。
pthread_mutex_init(android_app^.mutex, nil);//创建一个线程同步对象 mutex互斥体,
pthread_cond_init(android_app^.cond, nil);//创建一个线程通信的对象。用于主线程(UI线程)和我们的线程通信。
然后检查看看android系统之前是否已经为我们的应用程序保存过状态。有的话直接恢复就好了。另外比较重要的是android应用程序的屏幕方向变化的话,activity也要从新建立!!!!!
然后创建两个管道对象,一个让线程用来读取消息,一个用来写入消息
pipe(PipeDescriptors);
android_app^.msgread  := PipeDescriptors.ReadDes; //读取消息
android_app^.msgwrite := PipeDescriptors.WriteDes; //写
然后创建线程,运行程序代码
pthread_attr_init(attr);
pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
pthread_create(thread, attr, @android_app_entry, android_app);//创建线程,线程入口为android_app_entry,入口的参数为android_app
//开始等待线程运行起来
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);
运行完了之后返回android_app结构,这样就相当于我们的这个activity的oncreate完成了。
然后看一下android_app_entry的这个线程入口函数
function android_app_entry(param: Pointer): Pointer; cdecl;

// Delphi: init system unit and RTL.
procedure SystemEntry;
type
TMainFunction = procedure;
var
DlsymPointer: Pointer;
EntryPoint: TMainFunction;
begin
DlsymPointer := dlsym(RTLD_DEFAULT, '_NativeMain');
if DlsymPointer <> nil then
begin
EntryPoint := TMainFunction(DlsymPointer);
EntryPoint;
end;
end; var
android_app: Pandroid_app;
looper: PALooper;
begin
android_app := Pandroid_app(param);
android_app^.config := AConfiguration_new;//创建应用程序config
AConfiguration_fromAssetManager(android_app^.config, android_app^.activity^.assetManager); //从主线程获取消息用
android_app^.cmdPollSource.id := LOOPER_ID_MAIN;
android_app^.cmdPollSource.app := android_app;
android_app^.cmdPollSource.process := @process_cmd;//设置处理cmd的命令的函数
android_app^.inputPollSource.id := LOOPER_ID_INPUT;
android_app^.inputPollSource.app := android_app;
android_app^.inputPollSource.process := @process_input;//输入事件处理的函数 //创建一个looper消息循环,用来抓取消息
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 := ; //设置,让线程从等待开启运行中退出,也就是从android_app_create中退出
pthread_cond_broadcast(android_app^.cond);
pthread_mutex_unlock(android_app^.mutex); { Delphi: this will initialize System and any RTL related functions, call unit initialization sections and then
project main code, which will enter application main loop. This call will block until the loop ends, which is
typically signalled by android_app^.destroyRequested. }
SystemEntry;//这里才是调用了工程文件的Begin End之间的代码,是Delphi的一个封装,实际上,在Android Native中调用的是android_main(android_app);然后再这里执行一些消息的处理,等待程序运行结束
{ This place would be ideal to call unit finalization, class destructors and so on. }
// Halt; android_app_destroy(android_app);//销毁android_app退出线程。这里实际上才是Android程序的终结 Result := nil;
end;
然后是
function android_app_read_cmd(android_app: Pandroid_app): ShortInt; cdecl;
var
cmd: ShortInt;
begin
Result := -;
if __read(android_app^.msgread, @cmd, sizeof(cmd)) = SizeOf(cmd) then
begin
case cmd of
APP_CMD_SAVE_STATE:
free_saved_state(android_app);//释放当前的保存状态
end;
Result := cmd;
end;
end; procedure android_app_pre_exec_cmd(android_app: Pandroid_app; cmd: ShortInt); cdecl; //准备执行命令状态
begin
case cmd of
APP_CMD_INPUT_CHANGED:
begin
pthread_mutex_lock(android_app^.mutex);
if android_app^.inputQueue <> nil then
AInputQueue_detachLooper(android_app^.inputQueue);
android_app^.inputQueue := android_app^.pendingInputQueue;
if android_app^.inputQueue <> nil then
AInputQueue_attachLooper(android_app^.inputQueue, android_app^.looper, LOOPER_ID_INPUT, nil,
@android_app^.inputPollSource);
pthread_cond_broadcast(android_app^.cond);
pthread_mutex_unlock(android_app^.mutex);
end; APP_CMD_INIT_WINDOW:
begin
pthread_mutex_lock(android_app^.mutex);
android_app^.window := android_app^.pendingWindow;
pthread_cond_broadcast(android_app^.cond);
pthread_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:
begin
pthread_mutex_lock(android_app^.mutex);
android_app^.activityState := cmd;
pthread_cond_broadcast(android_app^.cond);
pthread_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 := ;
end;
end; procedure android_app_post_exec_cmd(android_app: Pandroid_app; cmd: ShortInt); cdecl;
begin
case cmd of
APP_CMD_TERM_WINDOW:
begin
pthread_mutex_lock(android_app^.mutex);
android_app^.window := nil;
pthread_cond_broadcast(android_app^.cond);
pthread_mutex_unlock(android_app^.mutex);
end; APP_CMD_SAVE_STATE:
begin
pthread_mutex_lock(android_app^.mutex);
android_app^.stateSaved := ;
pthread_cond_broadcast(android_app^.cond);
pthread_mutex_unlock(android_app^.mutex);
end; APP_CMD_RESUME:
{ Delphi: It is unclear why this line is necessary in original AppGlue, but it prevents FireMonkey applications
from recovering saved state. FireMonkey recovers saved state usually after APP_CMD_INIT_WINDOW, which happens
much later after CMD_RESUME. }
{ free_saved_state(android_app) };
end;
end; procedure process_cmd(app: Pandroid_app; source: Pandroid_poll_source); cdecl;
var
cmd: ShortInt;
begin
cmd := android_app_read_cmd(app);//先读取命令
android_app_pre_exec_cmd(app, cmd);//准备命令
if Assigned(app^.onAppCmd) then //程序内部的指令处理
app^.onAppCmd(app, cmd);
android_app_post_exec_cmd(app, cmd);//执行处理
end;

这些代码将在Android消息循环中处理调用

其实这些代码中很多地方都是有注释的。仔细看看就明白了。
 

然后程序进入工程文件的Begin End之间,先进入SysInit.pas单元的_InitExe,然后会调用GetThisModuleHandle,这个会调用dlopen(Info.dli_fname, RTLD_LAZY)就是相当于加载Windows的DLL,会先加载(Lib+程序名.so)获得当前句柄,然后dlClose关闭,最后程序以这个工程的库句柄作为程序的Hinstance,也就是说我们的好多资源应该会都打包到这个so中去,最后如果是Android环境,会调用_StartExe,来启动程序,_StartExe中会调用InitUnits来初始化一些单元,这里就会调用程序所引用到的各个单元的Initialization中的内容,在这个过程中会初始化FMX.PlatForm这个跨平台单元的TPlatformServices类库,本库是跨平台单元服务管理,然后就会调用FMX.PlatForm下的initialization,里面的RegisterCorePlatformServices会根据选择的平台来判定到底调用哪个平台下的RegisterCorePlatformServices,这个判定通过编译预处理指令在Implemention下的Use中

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},在ANdroid下,就会调用FMX.PlatForm.Android中的RegisterCorePlatformService来注册核心平台服务,然后里面有
if Assigned(PlatformAndroid.FAndroidApp) then
  begin
    PlatformAndroid.FAndroidApp^.onAppCmd := @HandleAndroidCmd;
    PlatformAndroid.FAndroidApp^.onInputEvent := @HandleAndroidInputEvent;
  end;
这样就将前面所说的Android的消息和输入事件转到FMX平台的HandleAndroidCmd和HandleAndroidInputEvent函数中然后HandleApplicationEvent中就会和消息管理器TMessageManager结合对消息进行处理。
把这些单元中的一些初始化过程都搞完了,就执行到工程文件中的Begin ENd之间去处理代码了,最后执行了Application.Run;
然后我们看这个执行的代码
procedure TApplication.Run;
var
AppService: IFMXApplicationService;
begin
{$IFNDEF ANDROID}
AddExitProc(DoneApplication);
{$ENDIF}
FRunning := True;
try
if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationService, AppService) then
AppService.Run;
finally
FRunning := False;
end;
end;
实际上他是通过跨平台服务获得当前运行程序的服务平台,也就是FMX.PlatForm.Android中的TPlatformAndroid,此类继承了IFMXApplicationService,并且在前面已经通过RegisterCorePlatformServices注册了TPlatformAndroid,所以这里实际上调用的就是TPlatformAndroid的Run过程,这个Run实际上就是开始跑Android的消息循环处理了。代码很短,实际上就是调用了InternalProcessMessages来进行内部消息循环处理
procedure TPlatformAndroid.Run;
begin
{ Although calling this routine is not really necessary, but it is a way to ensure that "Androidapi.AppGlue.pas" is
kept in uses list, in order to export ANativeActivity_onCreate callback. }
app_dummy; repeat
InternalProcessMessages;
until FAndroidApp^.destroyRequested <> ;
end;
首先InternalProcessMessages中有
EventPollValue := ALooper_pollAll(GetAndUpdateTimeout, nil, nil, PPointer(@PEventPollSource));
先通过这个获得消息信息,如果获得到了就有
if (PEventPollSource <> nil) and Assigned(PEventPollSource^.process) then
    begin
      PEventPollSource^.process(FAndroidApp, PEventPollSource);
      if EventPollValue = LOOPER_ID_MAIN then
        HasEvents := True;
    end
PEventPollSource^.process(FAndroidApp, PEventPollSource);这句会调用之前设定初始化的Process_Cmd或者Process_Input
这样,就将消息和实际关联起来了。至于显示Android的界面,则会通过TWindowManager.Current.RenderIfNeeds来判定是否需要渲染界面信息,如果需要则会调用TWindowManager.Render来进行界面渲染,最后Render函数中
procedure RenderNormalWindows;
  var
    I: Integer;
    PaintControl: IPaintControl;
  begin
    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这个则开始匹配FMXForm的PaintRects函数来进行界面信息绘制。于是一个Android程序开启运行到显示基本完成。

Delphi Android程序启动过程的更多相关文章

  1. Android程序启动过程深入解析

    当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么样的? 什么是Linux内核? 桌面系统linux内核与Android系统linux内核有什么区别? 什么是引导装载程序 ...

  2. Zygote和System进程的启动过程、Android应用进程启动过程

    1.基本过程 init脚本的启动Zygote Zygote进程的启动 System进程的启动 Android应用进程启动过程 2.init脚本的启动 +------------+ +-------+ ...

  3. Envoy 源码分析--程序启动过程

    目录 Envoy 源码分析--程序启动过程 初始化 main 入口 MainCommon 初始化 服务 InstanceImpl 初始化 启动 main 启动入口 服务启动流程 LDS 服务启动流程 ...

  4. Android应用程序启动过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6689748 前文简要介绍了Android应用程 ...

  5. Android 应用程序启动过程源代码分析

    本文转自:http://blog.csdn.net/luoshengyang/article/details/6689748 前文简要介绍了Android应用程序的Activity的启动过程.在And ...

  6. Android应用程序启动过程(二)分析

    本文依据Android6.0源码,从点击Launcher图标,直至解析到MainActivity#OnCreate()被调用. Launcher简析 Launcher也是个应用程序,不过是个特殊的应用 ...

  7. Delphi开发 Android 程序启动画面简单完美解决方案

    原文在这里 还是这个方法好用,简单!加上牧马人做的自动生成工具,更是简单. 以下为原文,向波哥敬礼! 前面和音儿一起研究 Android 下启动画面的问题,虽然问题得到了解决,但是,总是感觉太麻烦,主 ...

  8. Android应用程序启动过程(一)总结

    一.App启动方式 1,冷启动 冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用. 冷启动的特点:因为系统会重新创建一个新的进程分配给它,所以会创建和初始化App ...

  9. 比较windows phone程序启动和android程序启动原理

    windows phone 程序是如何启动的了,他和android程序有什么区别,我们重点从native code 层面来分析 在windows phone 程序启动的时候是: 在XAML中使用应用程 ...

随机推荐

  1. 基于VC的声音文件操作(三)

    (四)VC中相关的操作 1.mmioOpen 打开一个文件 Syntax MMIO mmioOpen( LPTSTR szFilename, LPMMIOINFO lpmmioinfo, DWORD ...

  2. js 操作map对象

    转自:http://smallvq123.javaeye.com/blog/823923 /* * Map对象,实现Map功能 * * * size() 获取Map元素个数 * isEmpty() 判 ...

  3. 【概念笔记】JAVA基础 - part2

    IT`huhiu前言录 这是续JAVA基础 - part1 链接http://www.cnblogs.com/ithuhui/p/5922067.html的. 笔记慢慢在修改和补充 JAVA里面重要的 ...

  4. [Orchard] 通过指定RouteData设置Pager的链接地址

    Orchard 中的Pager是一个很方便的用来分页的Shape, 但默认情况下,它是使用当前Action的地址作为链接地址,如果分页的数据要是由别的Action提供时,这样的分页链接就不对了,其实它 ...

  5. IP协议

    因特网协议(Internet Protocol, IP)是Internet的核心协议之一, 工作在网络层.IP协议提供节点间的寻址,路由以及顺序控制, 流量控制等服务. IP协议分为IPv4和IPv6 ...

  6. 微软BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)

    [公告]本博客于2015年10月起不再更新 新博客文章主要发表在商业智能BI社区: http://www.flybi.net/blog/biwork 博客地图自动分类 文章目录方便更好的导航,阅读文章 ...

  7. Python变量/运算符/函数/模块/string

    Python笔记(一) 1.变量类型 Python 有五个内置的简单类型:bool.int.long.float 和 complex.这些类型是不可变的,就是说整数对象一旦创建,其类型便不可更改. t ...

  8. [计算机图形学] 基于C#窗口的Bresenham直线扫描算法、种子填充法、扫描线填充法模拟软件设计(二)

    上一节链接:http://www.cnblogs.com/zjutlitao/p/4116783.html 前言: 在上一节中我们已经大致介绍了该软件的是什么.可以干什么以及界面的大致样子.此外还详细 ...

  9. [MFC] CList

    1.CList说明 类CList支持可按顺序或按值访问的非唯一对象的有序列表.CList 列表与双链接列表行为相似. template < class TYPE, class ARG_TYPE ...

  10. 我的fckeditor实践

    一开始我不懂这个ConnectorServlet是何用处,后来发现是专门用于文件上传的,因为fckeditor默认是不支持这个功能的. ConnectorServlet: /* * FCKeditor ...