写android纯c++的程序需要用到NativeActivity,这个NativeActivity就是一个一般的java类, 和普通的activity没有区别。
NativeActivity 是android sdk自带的一个activity。
android的纯c++的程序也是需要一个java虚拟机来运行的。
nativeActivity通过native_app_glu来启动我们的c++线程,传递各种activity事件给我的c++代码。
native_app_glu在ndk的sources\android目录里面,
将native_app_glu当做我们工程的静态库,这个静态库里面封装好了,会创建一个线程,
这个线程里面会调用一个android_main(android_app* pApplication)的函数,
因此,我们c++这边的入口函数就是android_main()
我们在这个android_main()函数里面的任务就是进行消息循环,做各种任务。
在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);
过程就这么简单,完了,现在分析下android_app_create这个函数:
static struct android_app* android_app_create(ANativeActivity* activity,
void* savedState, size_t savedStateSize) {
//首先创建一个android_app结构体,这个结构体参见android_native_app_glue.h
struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
memset(android_app, 0, sizeof(struct android_app));
android_app->activity = activity; //设置app的activity
pthread_mutex_init(&android_app->mutex, NULL); //创建一个线程同步对象 mutex互斥体,
pthread_cond_init(&android_app->cond, NULL); //创建一个条件变量。用于线程同步
//检查看看android系统之前是否已经为我们的应用程序保存过状态。有的话直接恢复就好了。
//还有比较重要的一条信息,android应用程序的屏幕方向变化的话,activity也要从新建立!!!!!
if (savedState != NULL) {
android_app->savedState = malloc(savedStateSize);
android_app->savedStateSize = savedStateSize;
memcpy(android_app->savedState, savedState, savedStateSize);
}
//创建两个管道对象,用于线程读写消息时同步。
int msgpipe[2];
if (pipe(msgpipe)) {
LOGE("could not create pipe: %s", strerror(errno));
return NULL;
}
android_app->msgread = msgpipe[0];
android_app->msgwrite = msgpipe[1];
//创建我们的线程,我们的代码就是运行在这个线程里面的,
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//这里指定了线程入口函数,和一个userdata数据就是android_app这个结构体。
pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
//等待我们的线程启动.
pthread_mutex_lock(&android_app->mutex);
//等待我们的线程启动,
while (!android_app->running) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
//我们的线程启动完了之后,返回这个结构体。这样activity的oncreate就完成了。
//主线程中剩下的代码就在做各种事件消息的路由。
return android_app;
}
现在来看看我们的线程的入口函数:android_app_entry,
static void* android_app_entry(void* param) {
//param是上面的函数创建线程的时候传进来的。
struct android_app* android_app = (struct android_app*)param;
//创建应用程序config
android_app->config = AConfiguration_new();
AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
//通过log打印应用的config
print_cur_config(android_app);
//从主线程抓取消息用的
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消息循环,抓取消息。
ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
&android_app->cmdPollSource);
android_app->looper = looper;
pthread_mutex_lock(&android_app->mutex);
android_app->running = 1; //这里这么设置activity的oncreate函数就会退出。
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
android_main(android_app); //调用我们的代码的入口函数。在我们自己实现的的这个入口函数里面
//在消息循环里面不断的抓取消息处理,或做其他事情,直到控制退出,然后
//这个线程才会结束。
android_app_destroy(android_app); //销毁android_app退出线程。
return NULL;
}
处理cmd的函数:
static void process_cmd(struct android_app* app, struct android_poll_source* source) {
int8_t cmd = android_app_read_cmd(app);
android_app_pre_exec_cmd(app, cmd);
if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
android_app_post_exec_cmd(app, cmd);
}
处理输入的函数
static void process_input(struct android_app* app, struct android_poll_source* source) {
AInputEvent* event = NULL;
if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
LOGV("New input event: type=%d\n", AInputEvent_getType(event));
if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
return;
}
int32_t handled = 0;
if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);//这里交给android_app的onInputEvent
//去处理,也就是我们自己写的输入处理函数。
AInputQueue_finishEvent(app->inputQueue, event, handled);
} else {
LOGE("Failure reading next input event: %s\n", strerror(errno));
}
}
typedef struct ANativeActivity {
/**
* 指向一个拥有各种事件回调函数的结构体指针,onStart,onResume,onPause,onStop,onDestroy
*/
struct ANativeActivityCallbacks* callbacks;
/**
* The global handle on the process's Java VM.
*/
JavaVM* vm;
/**
* JNI context for the main thread of the app. Note that this field
* can ONLY be used from the main thread of the process; that is, the
* thread that calls into the ANativeActivityCallbacks.
*/
JNIEnv* env;
/**
* The NativeActivity object handle.
*
* IMPORTANT NOTE: This member is mis-named. It should really be named
* 'activity' instead of 'clazz', since it's a reference to the
* NativeActivity instance created by the system for you.
*
* We unfortunately cannot change this without breaking NDK
* source-compatibility.
*/
jobject clazz;
/**
* Path to this application's internal data directory.
*/
const char* internalDataPath;
/**
* Path to this application's external (removable/mountable) data directory.
*/
const char* externalDataPath;
/**
* The platform's SDK version code.
*/
int32_t sdkVersion;
/**
* This is the native instance of the application. It is not used by
* the framework, but can be set by the application to its own instance
* state.
*/
void* instance; //这个用于指向android_app了。
/**
* Pointer to the Asset Manager instance for the application. The application
* uses this to access binary assets bundled inside its own .apk file.
*/
AAssetManager* assetManager;
} ANativeActivity;