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
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实现的效果,默认显示的黑色的屏幕,当手指在屏幕点击时,会根据手指的坐标,除上屏幕的宽高,计算出一个颜色值,来设置屏幕刷新的颜色。