UE4启动GameActivity
UE Android項目工程中的GameActivity基于NativeActivity,相關知識請參考之前的一篇文章,NativeActivity介紹
在之前NativeActivity介紹中,我們知道膠水層app_native_app_glue會創建一個子線程并prepare()開啟loop循環。UE中這個線程又叫做GameThread,用于處理游戲邏輯業務。初次之外,通過android_main()入口,在UE4引擎代碼LaunchAndroid中會創建一個AndroidProcessEvents,用來輪詢并處理cmd命令和input事件。
android_main()
void android_main(struct android_app* state) { //STEP1 獲取當前GameThread線程Id,并將android_app賦值給到GNativeAndroidAppGGameThreadId = FPlatformTLS::GetCurrentThreadId();BootTimingPoint("android_main");FPlatformMisc::LowLevelOutputDebugString(TEXT("Entering native app glue main function"));GNativeAndroidApp = state;check(GNativeAndroidApp); //STEP2 創建新的AndroidEventThreadWorker線程,用來處理cmd和input事件。 //關于這兩類事件,可以參考源碼文檔中 //https://cs.android.com/android/platform/superproject/+/master:prebuilts/ndk/current/sources/android/native_app_glue/android_native_app_glue.h 對android_app數據結構的注解pthread_attr_t otherAttr; pthread_attr_init(&otherAttr);pthread_attr_setdetachstate(&otherAttr, PTHREAD_CREATE_DETACHED);pthread_create(&G_AndroidEventThread, &otherAttr, AndroidEventThreadWorker, state);FPlatformMisc::LowLevelOutputDebugString(TEXT("Created event thread"));// Make sure glue isn't stripped. (not needed in ndk-15) #if PLATFORM_ANDROID_NDK_VERSION < 150000app_dummy(); #endif //STEP3 進入到GameThread的主循環,里面會初始化ue引擎以及定時tick//@todo android: replace with native activity, main loop off of UI thread, etc.AndroidMain(state); }android_main做了三件事情
AndroidMain()
//Main function called from the android entry point int32 AndroidMain(struct android_app* state) {BootTimingPoint("AndroidMain");FPlatformMisc::LowLevelOutputDebugString(TEXT("Entered AndroidMain()\n"));// Force the first call to GetJavaEnv() to happen on the game thread, allowing subsequent calls to occur on any threadFAndroidApplication::GetJavaEnv();// Set window format to 8888ANativeActivity_setWindowFormat(state->activity, WINDOW_FORMAT_RGBA_8888);//balabala...//阻塞等待ResumeMainInit被調用// wait for java activity onCreate to finish{SCOPED_BOOT_TIMING("Wait for GResumeMainInit");while (!GResumeMainInit){FPlatformProcess::Sleep(0.01f);FPlatformMisc::MemoryBarrier();}}// read the command line fileInitCommandLine();// ready for onCreate to completeGEventHandlerInitialized = true;// 初始化文件掛載// Initialize file system access (i.e. mount OBBs, etc.).// We need to do this really early for Android so that files in the// OBBs and APK are found.IPlatformFile::GetPlatformPhysical().Initialize(nullptr, FCommandLine::Get());// balabala...// pre初始化游戲引擎// initialize the engine int32 PreInitResult = GEngineLoop.PreInit(0, NULL, FCommandLine::Get());// 若pre初始化失敗直接退出游戲線程if (PreInitResult != 0){checkf(false, TEXT("Engine Preinit Failed"));return PreInitResult;}// balabala...// 初始化游戲引擎GEngineLoop.Init();bDidCompleteEngineInit = true;UE_LOG(LogAndroid, Log, TEXT("Passed GEngineLoop.Init()"));// balabala...//開始TICK// tick until donewhile (!IsEngineExitRequested()){FAndroidStats::UpdateAndroidStats();FAppEventManager::GetInstance()->Tick();if(!FAppEventManager::GetInstance()->IsGamePaused()){GEngineLoop.Tick();}else{// use less CPU when pausedFPlatformProcess::Sleep(0.10f);}//balabala...}//退出游戲則走到這里來FAppEventManager::GetInstance()->TriggerEmptyQueue();UE_LOG(LogAndroid, Log, TEXT("Exiting"));// exit out!GEngineLoop.Exit();UE_LOG(LogAndroid, Log, TEXT("Exiting is over"));FPlatformMisc::RequestExit(1);return 0; }AndroidMain中做了這么幾件事情
Activity生命周期處理和input輸入事件處理
通過NativeActivity一文,我們梳理了cmd和input事件的處理流程
而在UE項目中,在AndroidEventThreadWorker中實現了onAppCmd()和onInputEvent()方法,用來響應cmd和input事件
OnAppCommandCB方法中會處理事件,并且將有關的事件推到UE自身的queue(GameThread中)中,并且在下一次tick到來的時候消費掉
//Called from the event process thread static void OnAppCommandCB(struct android_app* app, int32_t cmd) {check(IsInAndroidEventThread());static bool bDidGainFocus = false;//FPlatformMisc::LowLevelOutputDebugStringf(TEXT("OnAppCommandCB cmd: %u, tid = %d"), cmd, gettid());static bool bHasFocus = false;static bool bHasWindow = false;static bool bIsResumed = false;// Set event thread's view of the window dimensions:{ANativeWindow* DimensionWindow = app->pendingWindow ? app->pendingWindow : app->window;if (DimensionWindow){FAndroidWindow::SetWindowDimensions_EventThread(DimensionWindow);}}switch (cmd){case APP_CMD_SAVE_STATE:/*** Command from main thread: the app should generate a new saved state* for itself, to restore from later if needed. If you have saved state,* allocate it with malloc and place it in android_app.savedState with* the size in android_app.savedStateSize. The will be freed for you* later.*/// the OS asked us to save the state of the appUE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_SAVE_STATE"));//推送到UE的QUEUE中,最終在tick()執行的時候消費掉FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_SAVE_STATE);break;//balabala....}//balabala... }在AndroidEventManager.cpp中實現了Tick()
void FAppEventManager::Tick() {check(IsInGameThread());while (!Queue.IsEmpty()){FAppEventPacket Event = DequeueAppEvent();FPlatformMisc::LowLevelOutputDebugStringf(TEXT("FAppEventManager::Tick processing, %d"), int(Event.State));switch (Event.State){case APP_EVENT_STATE_WINDOW_CREATED:FAndroidWindow::EventManagerUpdateWindowDimensions(Event.Data.WindowWidth, Event.Data.WindowHeight);bCreateWindow = true;break;case APP_EVENT_STATE_WINDOW_RESIZED:// Cache the new window's dimensions for the game thread.FAndroidWindow::EventManagerUpdateWindowDimensions(Event.Data.WindowWidth, Event.Data.WindowHeight);ExecWindowResized();break;case APP_EVENT_STATE_WINDOW_CHANGED:// React on device orientation/windowSize changes only when application has window// In case window was created this tick it should already has correct size// see 'Java_com_epicgames_ue4_GameActivity_nativeOnConfigurationChanged' for event thread/game thread mismatches.ExecWindowResized();break;case APP_EVENT_STATE_SAVE_STATE:bSaveState = true; //todo android: handle save state.break;//balabala...}//balabala... }這里涉及到多個線程的通信,事件傳遞后續會以線程間傳遞的方式來介紹
UIThread (Android sdk)
GameThread (Android NDK創建,NDK和UE都使用)
AndroidEventThread(UE創建并使用)
總結
以上是生活随笔為你收集整理的UE4启动GameActivity的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [leetcode]Generate P
- 下一篇: 服务发现与健康监测框架Consul-DN