NativeActivity使用流程

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實現的效果,默認顯示的黑色的屏幕,當手指在屏幕點擊時,會根據手指的座標,除上屏幕的寬高,計算出一個顏色值,來設置屏幕刷新的顏色。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章