NativeActivity.java的使用中,屏幕繪製的操作是用native代碼實現(如C++),顯示UI的窗口跟普通的java層app是一樣的,也是一個Activity.java,就是NativeActivity.java,所以從他的onCreate方法看起:
https://www.khronos.org/registry/OpenGL-Refpages/es3/
https://www.khronos.org/registry/EGL/sdk/docs/man/
https://github.com/android/ndk-samples/blob/master/native-activity/app/src/main/cpp/main.cpp
W:\Android\LA.UM.7.6\LINUX\android\frameworks\base\core\java\android\app\NativeActivity.java
這裏會去加載一個本地庫libname = "main",並查找本地庫中的入口函數funcname = "ANativeActivity_onCreate";當然庫的名字,入口函數名字都是可以修改,修改要在androidManifest.xml中用meta-data指定,
@Override
protected void onCreate(Bundle savedInstanceState) {
mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
getAbsolutePath(getExternalFilesDir(null)),
Build.VERSION.SDK_INT, getAssets(), nativeSavedState,
classLoader, classLoader.getLdLibraryPath());
}
W:Android\LA.UM.7.6\LINUX\android\frameworks\base\core\jni\android_app_NativeActivity.cpp
這裏的code是一個unique_ptr指針,調用release()返回了一個普通指針,傳給了java層,後續java層把這個普通指針再傳回native層,轉成NativeCode* code = (NativeCode*)handle;來使用。
這裏是藉助android ndk提供的一個靜態庫android_native_app_glue.c,實現一個執行模型,在不同的線程實現app自己的主事件循環。
static jlong
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
jobject messageQueue, jstring internalDataDir, jstring obbDir,
jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,
jbyteArray savedState, jobject classLoader, jstring libraryPath) {
code->createActivityFunc(code.get(), rawSavedState, rawSavedSize);
...
return (jlong)code.release();
}
W:\Android\LA.UM.7.6\LINUX\android\prebuilts\ndk\r16\sources\android\native_app_glue\android_native_app_glue.c
這裏提供NativeActivity.java中需要的入口函數:JNIEXPORT
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState,
size_t savedStateSize)
然後新建一個線程,運行應用自己實現的android_main方法。應用在android_main中處理activity生命週期的事件處理,及input事件的處理。
JNIEXPORT
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState,
size_t savedStateSize) {
LOGV("Creating: %p\n", activity);
activity->callbacks->onDestroy = onDestroy;
activity->callbacks->onStart = onStart;
activity->callbacks->onResume = onResume;
activity->callbacks->onSaveInstanceState = onSaveInstanceState;
activity->callbacks->onPause = onPause;
activity->callbacks->onStop = onStop;
activity->callbacks->onConfigurationChanged = onConfigurationChanged;
activity->callbacks->onLowMemory = onLowMemory;
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
activity->instance = android_app_create(activity, savedState, savedStateSize);
}
W:\Android\LA.UM.7.6\LINUX\android\prebuilts\ndk\r16\sources\android\native_app_glue\android_native_app_glue.c
// --------------------------------------------------------------------
// Native activity interaction (called from main thread)
// --------------------------------------------------------------------
static struct android_app* android_app_create(ANativeActivity* activity,
void* savedState, size_t savedStateSize) {
pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
}
W:\Android\LA.UM.7.6\LINUX\android\prebuilts\ndk\r16\sources\android\native_app_glue\android_native_app_glue.c
static void* android_app_entry(void* param) {
android_main(android_app);
}
/**
* This is the main entry point of a native application that is using
* android_native_app_glue. It runs in its own thread, with its own
* event loop for receiving input events and doing other things.
*/
void android_main(struct android_app* state) {}
* 1/ The application must provide a function named "android_main()" that
* will be called when the activity is created, in a new thread that is
* distinct from the activity's main thread.
在activity的oncreate被調用時,在非主線程中,會調用android_main()函數,所以應用程序需要提供一個這樣的函數。
爲什麼是非主線程中呢?因爲在
static struct android_app* android_app_create(ANativeActivity* activity,
void* savedState, size_t savedStateSize){}
創建了新的線程android_app_entry,來執行應用程序的入口函數。
android_main(struct android_app *state)函數參數,接收一個android_app的結構體,這個結構體的構建是在android_app_create()@android_native_app_glue.c中
這個結構體中包含了一些重要對象的引用,如:ANativeActivity,這個ANativeActivity就是運行這個應用程序的實例。
往上回溯這個ANativeActivity就是loadNativeCode_native()@android_app_NativeActivity.cpp中的,std::unique_ptr<NativeCode> code;
struct NativeCode : public ANativeActivity {
}
ANativeActivity 的定義在native_activity.h中。
android_app持有一個ALooper instance實例來監聽兩個重要的事情:
一個activity生命週期事件:APP_CMD_START等
一個是跟activity關聯的AInputQueue的輸入事件。
在收到事件後,返回數據會指向一個android_poll_source的結構體,然後調用結構體中的process函數處理事件,同時會往process中填充android_app->OnAppCmd,android_app->onInputEvent數據。
看事件處理的具體流程:
android_main()函數的實現類:https://github.com/android/ndk-samples/blob/master/native-activity/app/src/main/cpp/main.cpp
void android_main(struct android_app* state) {
struct engine engine{};
memset(&engine, 0, sizeof(engine));
state->userData = &engine;
state->onAppCmd = engine_handle_cmd;
state->onInputEvent = engine_handle_input;
engine.app = state;
}
在android_main()中指定了activity生命週期的處理實現,及input事件的處理實現。
這樣在android_native_app_glue.c中分發事件時process_cmd,process_input時,會調用到上面指定的處理實現。
這個開源的main.app實現的效果,默認顯示的黑色的屏幕,當手指在屏幕點擊時,會根據手指的座標,除上屏幕的寬高,計算出一個顏色值,來設置屏幕刷新的顏色。