NativeActivity工程编译及运行

来源:互联网 发布:blending 算法 编辑:程序博客网 时间:2024/05/14 19:15

// android-ndk-r8e/samples/native-activity

用eclipse创建一个已经存在的工程,把这个native-activity创建行eclipse即可。具体步骤:右键->New Android Project->Create project from existing source,然后location选好你的native-activity工程即可。

编译ndk工程很简单,开始进入CMD命令,然后切到工程目录,如我的:D:\develop\android-ndk-r8e\samples\native-activity,最后输入D:\develop\android-ndk-r8e\ndk-build即可,当然了,你可以配置到环境变量,只需输入ndk-build。


native-activity/AndroidManifest.xml 文件内容:


<?xml version="1.0" encoding="utf-8"?><!-- BEGIN_INCLUDE(manifest) --><manifest xmlns:android="http://schemas.android.com/apk/res/android"        package="com.example.native_activity"        android:versionCode="1"        android:versionName="1.0">    <!-- This is the platform API where NativeActivity was introduced. -->    <uses-sdk android:minSdkVersion="10" />    <!-- This .apk has no Java code itself, so set hasCode to false. -->    <application android:label="@string/app_name" android:hasCode="true">        <!-- Our activity is the built-in NativeActivity framework class.             This will take care of integrating with our NDK code. -->        <activity android:name="android.app.NativeActivity"                android:label="@string/app_name"                android:configChanges="orientation|keyboardHidden">            <!-- Tell NativeActivity the name of or .so -->            <meta-data android:name="android.app.lib_name"                    android:value="native-activity" />            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest> <!-- END_INCLUDE(manifest) -->

 <!-- This .apk has no Java code itself, so set hasCode to false. -->发现官网说没有JAVA代码就设置FALSE,但是这样运行偏偏不行,说找不到

Caused by: java.lang.IllegalArgumentException: Unable to find native library: main,GOOGLE了一下,发现问题所在,原来这个还是有JAVA代码的,这个string下面的app_name已经生成了JAVA代码,所以这个还是要设置true的。本人测试改为true确实可以正常运行。


native-activity/jni/Android.mk 文件内容:

# Copyright (C) 2010 The Android Open Source Project
# 版权所有(C)2010 Android 开源工程
#
# Licensed under the Apache License, Version 2.0 (the "License");
# 根据 2.0 版本 Apache 许可证授权
# you may not use this file except in compliance with the License.
# 根据本许可证,你可以不使用此文件。
# You may obtain a copy of the License at
# 你可以获得许可证的副本在
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# 除非因适用法律需要或书面同意,
# 根据许可证分发的软件是基于"按原样"原则提供,无任何明示的或暗示的保证或条件。
# See the License for the specific language governing permissions and
# limitations under the License.
# 详见根据许可证许可下,特定语言的管辖权限和限制。

# 用于返回当前目录的路径
LOCAL_PATH := $(call my-dir)

# CLEAR_VARS 变量是由生成系统已提供的,
# 并且指出一个特殊的 GNU Makefile 文件将为你清除除了 LOCAL_PATH 以外的许多的 LOCAL_XXX 变量,
# (例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES,等等...)
# 这是必须的,因为全部的生成控制文件是在一个单独的 GNU Make 执行环境中被分析的,在那里所有的变量是全局的。
include $(CLEAR_VARS)

# LOCAL_MODULE 变量必须是已定义的,用来标识你的 Android.mk 文件中描述的每个模块。
# 模块名字必须是唯一,并且不能包含任何的空格。
# 注意生成系统将自动添加适当的前缀和后缀到相应的产生文件。
# 换句话说,一个共享库模块命名为 native-activity 将产生 libnative-activity.so 。
LOCAL_MODULE    := native-activity

# LOCAL_SRC_FILES 变量必须包含将生成且汇编成一个模块的 C 和/或 C++ 源文件的列表。
# 注意你将不列出头文件和包含文件在这里,因为生成系统将自动地为你估算依赖;
# 列出的源文件将直接递给编译器。
LOCAL_SRC_FILES := main.c

# 使用在生成你的模块时的额外的链接器标志列表。
# 对于用 -l 前缀传递特定的系统库名是有用的。
# liblog.so       提供 Android 记录日志 API
# libandroid.so   提供 Android 功能访问 API
# libEGL.so       提供 EGL API
# libGLESv1_CM.so 提供 OpenGL ES API
# 注:
# OpenGL ES (OpenGL for Embedded Systems,以下简称 OpenGL)
# OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。
# 该 API 由 Khronos 集团定义推广,
# Khronos 是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
#
# EGL 是 OpenGL ES 和 底层本地平台视窗系统 之间的接口,为 OpenGL ES 提供平台独立性而设计。
# 它被用于处理图形管理、表面/缓冲捆绑、渲染同步,
# 以及支援使用其他 Khronos API 进行的高效、加速、混合模式 2D 和 3D 渲染。
LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM

# 将链接到本模块的静态库模块列表(用 BUILD_STATIC_LIBRARY 生成的)。
# 这仅在共享库模块中有意义。
LOCAL_STATIC_LIBRARIES := android_native_app_glue

# BUILD_SHARED_LIBRARY 是一个已由生成系统提供的变量,
# 表明一个 GNU Makefile 脚本是负责收集你定义的从最近的 include $(CLEAR_VARS)
# 到决定去生成之间的全部 LOCAL_XXX 变量的信息,然后正确地生成共享库。
# 注意你必须在包含这个文件之前最近位置有 LOCAL_MODULE 或 LOCAL_SRC_FILES 变量的定义。
include $(BUILD_SHARED_LIBRARY)

# $(call macro-name[, param1, ...])
# call 是一个内置于 make 的函数,
# call 会扩展它的第一个参数并把其余参数依次替换到出现 $1、$2、...的地方。
# call 的第一个参数可以是任何宏或变量的名称。
# 允许你通过名字查找且包含其它模块的 Android.mk 文件。
# 这将在你的 NDK_MODULE_PATH 环境变量提到的目录列表中查找模块标记的名字,
# 并自动地为你包含它的 Android.mk 文件。
# 为了方便起见,$NDK/sources 是被 NDK 生成系统附加到你的 NDK_MODULE_PATH 变量值定义中。
$(call import-module,android/native_app_glue)

native-activity/jni/main.c 文件内容:

/* * Copyright (C) 2010 The Android Open Source Project * 版权所有(C)2010 Android 开源工程 * * Licensed under the Apache License, Version 2.0 (the "License"); * 根据 2.0 版本 Apache 许可证授权 * you may not use this file except in compliance with the License. * 根据本许可证,你可以不使用此文件。 * You may obtain a copy of the License at * 你可以获得许可证的副本在 * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 除非因适用法律需要或书面同意, * 根据许可证分发的软件是基于"按原样"原则提供,无任何明示的或暗示的保证或条件。 * See the License for the specific language governing permissions and * limitations under the License. * 根据许可证分发的软件是基于"按原样"原则提供,无任何明示的或暗示的保证或条件。 *///BEGIN_INCLUDE(all)/* Java Native Interface */#include <jni.h>/* 错误报告机制 */#include <errno.h>/* EGL */#include <EGL/egl.h>/* OpenGL ES 1.x */#include <GLES/gl.h>/* 接收和处理传感器事件 */#include <android/sensor.h>/* Android logging API */#include <android/log.h>/* android-ndk-r5b/sources/android/native_app_glue 静态库头文件 */#include <android_native_app_glue.h>#define LOGI(...) \((void)__android_log_print( ANDROID_LOG_INFO, "native-activity", __VA_ARGS__ ))#define LOGW(...) \((void)__android_log_print( ANDROID_LOG_WARN, "native-activity", __VA_ARGS__ ))/** * Our saved state data. * 我们已保存的状态数据。 */struct saved_state{    float   angle; /* RGB 中的绿色值 */    int32_t x;     /* X 坐标 */    int32_t y;     /* Y 坐标 */};/** * Shared state for our app. * 为我们的应用程序共享状态。 */struct engine{    /* android_native_app_glue.h 中定义的本地应用程序粘合剂模块用数据结构 */    struct android_app* app;    /* sensor.h 中定义的传感器管理器 */    ASensorManager* sensorManager;    /* 加速度传感器 */    const ASensor* accelerometerSensor;    /* 已与一个循环器关联起来的传感器事件队列 */    ASensorEventQueue* sensorEventQueue;    /* 非零为可以绘制动画 */    int animating;    /* 显示器句柄 */    EGLDisplay display;    /* 系统窗口或 frame buffer 句柄 */    EGLSurface surface;    /* OpenGL ES 图形上下文 */    EGLContext context;    /* 系统窗口的宽度(像素) */    int32_t width;    /* 系统窗口的宽度(像素) */    int32_t height;    /* 我们已保存的状态数据 */    struct saved_state state;};/** * Initialize an EGL context for the current display. * 为当前显示器初始化一个 EGL 上下文。 */static intengine_init_display( struct engine* engine ){    /* initialize OpenGL ES and EGL     * 初始化 OpenGL ES 和 EGL     */    /*     * Here specify the attributes of the desired configuration.     * 在这里具体指定想要的配置的属性。     *     * Below, we select an EGLConfig with at least 8 bits per color     * component compatible with on-screen windows.     * 在下面,我们选择一个至少 8 位色的 EGLConfig 与屏幕上的窗口一致。     * 注:通常以 ID, Value 依次存放,对于个别标识性的属性可以只有 ID 没有 Value 。     */    const EGLint    attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, /* 系统窗口类型 */                  EGL_BLUE_SIZE,    8,              /* 蓝色位数 */                  EGL_GREEN_SIZE,   8,              /* 绿色位数 */                  EGL_RED_SIZE,     8,              /* 红色位数 */                  EGL_NONE };    /* 系统窗口的宽度(像素) */    EGLint     w;    /* 系统窗口的高度(像素) */    EGLint     h;    /* 未使用的变量 */    EGLint     dummy;    /* 像素格式ID - RGBA/RGBX/RGB565 */    EGLint     format;    /* 系统中 Surface 的 EGL 配置 的总个数 */    EGLint     numConfigs;    /* Surface 的 EGL 配置 */    EGLConfig  config;    /* 系统窗口句柄 */    EGLSurface surface;    /* OpenGL ES 图形上下文 */    EGLContext context;    /* 1.返回一个显示器连接 - 是一个关联系统物理屏幕的通用数据类型。 */    EGLDisplay display = eglGetDisplay( EGL_DEFAULT_DISPLAY ); /* 得到系统默认的 */    /* 原型:EGLDisplay eglGetDisplay ( NativeDisplayType display );     *    display 参数是本地系统显示器类型,取值为本地显示器 ID 值。     * 返回:如果系统中没有一个可用的本地显示器 ID 值与 display 参数匹配,     *    函数将返回 EGL_NO_DISPLAY ,而没有任何 Error 状态被设置。     */    /* 2. EGL 在使用前需要初始化,因此每个显示器句柄(EGLDisplay)在使用前都需要初始化。*/    eglInitialize( display, /* 有效的显示器句柄 */                   0,       /* 返回主版本号 - 不关心可设为 NULL 值或零(0) */                   0 );     /* 返回次版本号 - 不关心可设为 NULL 值或零(0) */    /* 原型:EGLBoolean eglInitialize( EGLDisplay dpy,     *                                EGLint*    major,     *                                EGLint*    minor );     *    EGLint 为 int 数据类型。     * 返回:EGLBOOlean 取值:EGL_TRUE = 1, EGL_FALSE = 0 。     */    /* Here, the application chooses the configuration it desires.     * 在这里,应用程序决定它要求的配置。     *     * In this sample, we have a very simplified selection process,     * where we pick the first EGLConfig that matches our criteria.     * 在这个示例中,我们有一个非常精简的选择处理,     * 我们选择第一个 EGLConfig 适应我们的标准。     */    /* 定义一个希望从系统获得的配置,它将返回一个最接近你的需求的配置 */    eglChooseConfig( display,       /* 有效的显示器句柄 */                     attribs,       /* 以 EGL_NONE 结束的参数数组 */                     &config,       /* Surface 的 EGL 配置 */                     1,             /* Surface 的 EGL 配置个数 */                     &numConfigs ); /* 系统中 Surface 的 EGL 配置 的总个数 */    /* 原型:EGLboolean eglChooseConfig( EGLDisplay    dpy,     *                                  const EGLint* attr_list,     *                                  EGLConfig*    config,     *                                  EGLint        config_size,     *                                  EGLint*       num_config );     */    /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig     * that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry().     * EGL_NATIVE_VISUAL_ID 是一个 EGLConfig 的属性,     * 保证被 ANativeWindow_setBuffersGeometry 函数认可。     *     * As soon as we picked a EGLConfig,     * we can safely reconfigure the ANativeWindow buffers to match,     * using EGL_NATIVE_VISUAL_ID.     * 我们已经挑选了一个 EGLConfig ,     * 使用 EGL_NATIVE_VISUAL_ID 我们可以安全地重新配置相应的 ANativeWindow 缓冲区了。     */    /* 查询 EGLConfig 的指定属性值 */    eglGetConfigAttrib( display,              /* 有效的显示器句柄 */                        config,               /* 有效的 Surface 的 EGL 配置 */                        EGL_NATIVE_VISUAL_ID, /* 与操作系统通讯的可视 ID 句柄 */                        &format );    /* 原型:EGLBoolean eglGetConfigAttrib( EGLDisplay display,     *                                     EGLConfig  config,     *                                     EGLint     attribute,     *                                     EGLint*    value );     */    /* 改变窗口表面像素格式和大小     * 参见:native_window.h */    ANativeWindow_setBuffersGeometry( engine->app->window, /* ANativeWindow */                                      0,                   /* 宽度(像素) */                                      0,                   /* 高度(像素) */                                      format );            /* 像素格式 */    /* 创建一个可实际显示的系统窗口句柄,实际上就是一个 FrameBuffer */    surface = eglCreateWindowSurface( display, /* 有效的显示器句柄 */                                      config,  /* 有效的 Surface 的 EGL 配置 */                                      engine->app->window, /* ANativeWindow */                                      NULL ); /* 属性列表可以是空,使用默认值 */    /* 原型:EGLSurface eglCreateWindowSurface( EGLDisplay          display,     *                                         EGLConfig           config,     *                                         EGLNatvieWindowType window,     *                                         const EGLint*       attribList );     */    /* 创建一个 OpenGL ES 图形上下文 */    context = eglCreateContext( display, /* 有效的显示器句柄 */                                config,  /* 有效的 Surface 的 EGL 配置 */                                NULL,    /* 不和其他 EGLContext 分享资源 */                                NULL );  /* 属性列表可以是空,使用默认值 */    /* 原型:EGLContext eglCreateContext( EGLDisplay    display,     *                                   EGLConfig     config,     *                                   EGLContext    shareContext,     *                                   const EGLint* attribList );     */    /* 激活 OpenGL ES 图形上下文     * 在 OpenGL ES ,一次只能有一个 context 生效。     */    if ( EGL_FALSE == eglMakeCurrent( display,     /* 有效的显示器句柄 */                                      surface,     /* 上面创建的系统窗口 */                                      surface,     /* 上面创建的系统窗口 */                                      context ) )  /* OpenGL ES 图形上下文 */    {        LOGW( "Unable to eglMakeCurrent" );        return -1;    }    /* 原型:EGLBoolean eglMakeCurrent( EGLDisplay display,     *                               EGLSurface draw,     *                               EGLSurface read,     *                               EGLContext context );     */    eglQuerySurface( display,    /* 有效的显示器句柄 */                     surface,    /* 上面创建的系统窗口 */                     EGL_WIDTH,  /* 返回系统窗口的宽度(像素) */                     &w );    /* 原型:EGLBoolean eglQuerySurface( EGLDisplay display,     *    EGLSurface surface,     *    EGLint     attribute,     *      EGLint*    value );     */    eglQuerySurface( display,                     surface,                     EGL_HEIGHT, /* 返回系统窗口的高度(像素) */                     &h );    engine->display = display;    engine->context = context;    engine->surface = surface;    engine->width = w;    engine->height = h;    engine->state.angle = 0;    /* Initialize GL state.     * 初始化 GL 状态。     */    glHint( GL_PERSPECTIVE_CORRECTION_HINT, /* 指定颜色和纹理坐标的插值质量 */            GL_FASTEST );                   /* 使用速度最快的模式 */    /* 开启服务端 GL 功能 */    glEnable( GL_CULL_FACE ); /* 开启多边形表面剔除功能 */    /* 原型:void glEnable( GLenum cap ); */    /* 启用光滑着色 */    glShadeModel( GL_SMOOTH );    /* 禁用服务端 GL 功能 */    glDisable( GL_DEPTH_TEST ); /* 禁用深度测试 */    return 0;}/** * Just the current frame in the display. * 只是当前帧在显示。 */static voidengine_draw_frame( struct engine* engine ){    /* 显示器句柄为空 */    if ( engine->display == NULL )    {        /* No display.         * 不显示。         */        return;    }    /* Just fill the screen with a color.     * 只是用一种颜色添充屏幕。     */    glClearColor( ( (float)engine->state.x ) / engine->width,                  engine->state.angle,                  ( (float)engine->state.y ) / engine->height,                  1 );    /* 原型:void glClearColor( GLclampf red,     *                       GLclampf green,     *                       GLclampf blue,     *                       GLclampf alpha );     */    /* 要清除颜色缓冲 */    glClear( GL_COLOR_BUFFER_BIT );    /* 原型:void glClear( GLbitfield mask ); */    /* 发送 EGL 系统窗口绘图缓冲区到本地窗口 */    eglSwapBuffers( engine->display,                    engine->surface );    /* 原型:EGLBoolean eglSwapBuffers( EGLDisplay display,     *                               EGLSurface surface );     */}/** * Tear down the EGL context currently associated with the display. * 拆掉与显示器关联的当前 EGL 上下文。 */static voidengine_term_display( struct engine* engine ){    if ( engine->display != EGL_NO_DISPLAY )    {        /* 解绑 OpenGL ES 图形上下文 与 可实际显示的系统窗口句柄 */        eglMakeCurrent( engine->display,                        EGL_NO_SURFACE,                        EGL_NO_SURFACE,                        EGL_NO_CONTEXT );        if ( engine->context != EGL_NO_CONTEXT )        {            /* 销毁 OpenGL ES 图形上下文 */            eglDestroyContext( engine->display,                               engine->context );        }        if ( engine->surface != EGL_NO_SURFACE )        {            /* 销毁 可实际显示的系统窗口句柄 */            eglDestroySurface( engine->display,                               engine->surface );        }        /* 终止一个显示器的连接 */        eglTerminate( engine->display );    }    /* 禁止动画绘制 */    engine->animating = 0;    /* 以防上面的判断出错,修改记录 */    engine->display = EGL_NO_DISPLAY;    engine->context = EGL_NO_CONTEXT;    engine->surface = EGL_NO_SURFACE;}/** * Process the next input event. * 处理下一个输入事件。 */static int32_tengine_handle_input( struct android_app* app,                     AInputEvent*        event ){    struct engine* engine = (struct engine*)app->userData;    /* 得到的输入事件类型为触摸屏事件 */    if ( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )    {        /* 启用动画绘制 */        engine->animating = 1;        /* 得到第一个触摸点的当前 x 坐标 */        engine->state.x = AMotionEvent_getX( event, 0 );        /* 得到第一个触摸点的当前 y 坐标 */        engine->state.y = AMotionEvent_getY( event, 0 );        return 1;    }    return 0;}/** * Process the next main command. * 处理下一个主线程命令消息。 */static voidengine_handle_cmd( struct android_app* app,                   int32_t             cmd ){    struct engine* engine = (struct engine*)app->userData;    switch ( cmd )    {    case APP_CMD_SAVE_STATE:        /* The system has asked us to save our current state.         * 系统告诉我们去保存我们的当前状态。         *         * Do so.         * 如下所做。         */        engine->app->savedState = malloc( sizeof( struct saved_state ) );        *( (struct saved_state*)engine->app->savedState ) = engine->state;        engine->app->savedStateSize = sizeof( struct saved_state );        break;    case APP_CMD_INIT_WINDOW:        /* The window is being shown, get it ready.         * 窗口是正在显示,准备得到它。         */        if ( engine->app->window != NULL )        {            engine_init_display( engine );            engine_draw_frame( engine );        }        break;    case APP_CMD_TERM_WINDOW:        /* The window is being hidden or closed, clean it up.         * 窗口是正在隐藏或关闭,清理它。         */        engine_term_display( engine );        break;    case APP_CMD_GAINED_FOCUS:       /* When our app gains focus, we start monitoring the accelerometer.        * 当我们的应用程序得到焦点时,我们开始监测加速器。        */       if ( engine->accelerometerSensor != NULL )       {           /* 启用指定的传感器 */           ASensorEventQueue_enableSensor( engine->sensorEventQueue,                                           engine->accelerometerSensor );           /* We'd like to get 60 events per second (in us).            * 我们将喜欢每秒得到六十个事件。            */           ASensorEventQueue_setEventRate( engine->sensorEventQueue,                                           engine->accelerometerSensor,                                           ( 1000L / 60 ) * 1000 );       }       break;    case APP_CMD_LOST_FOCUS:        /* When our app loses focus, we stop monitoring the accelerometer.         * 当我们的应用程序丢失焦点时,我们停止监测加速器。         *         * This is to avoid consuming battery while not being used.         * 在不使用时期避免消耗电池。         */        if ( engine->accelerometerSensor != NULL )        {            /* 禁用指定的传感器 */            ASensorEventQueue_disableSensor( engine->sensorEventQueue,                                             engine->accelerometerSensor );        }        /* Also stop animating.         * 同样禁止动画绘制。         */        engine->animating = 0;        engine_draw_frame( engine );        break;    }}/** * This is the main entry point of a native application * that is using android_native_app_glue. * 这是使用了 android_native_app_glue 粘合剂模块的一个本地应用程序的主入口点。 * * It runs in its own thread, * with its own event loop for receiving input events and doing other things. * 它运行在它自己的线程中,用它自己的事件循环来接收输入事件和做其它事情。 */voidandroid_main( struct android_app* state ){    struct engine engine;    /* Make sure glue isn't stripped.     * 务必粘合剂模块未剥离。     * 注:在 android_native_app_glue.c 文件中这是一个空函数。     */    app_dummy();    memset( &engine, 0, sizeof( engine ) );    /* 在应用程序各部分之间共享的数据 */    state->userData = &engine;    /* 指向一个处理最重要的应用程序命令的函数 */    state->onAppCmd = engine_handle_cmd;    /* 指向一个处理输入事件的函数 */    state->onInputEvent = engine_handle_input;    engine.app = state;    /* Prepare to monitor accelerometer.     * 准备监测加速器。     */    engine.sensorManager = ASensorManager_getInstance(); /* 传感器管理器为单例模式 */    /* 得到默认的加速度传感器 */    engine.accelerometerSensor = ASensorManager_getDefaultSensor( engine.sensorManager,                                                                  ASENSOR_TYPE_ACCELEROMETER );    engine.sensorEventQueue = ASensorManager_createEventQueue( engine.sensorManager,                                                               state->looper,                                                               LOOPER_ID_USER,                                                               NULL,                                                               NULL );    if ( state->savedState != NULL )    {        /* We are starting with a previous saved state;         * 我们使用一个之前保存状态启动。         *         * restore from it.         * 用它来恢复。         */        engine.state = *(struct saved_state*)state->savedState;    }    /* loop waiting for stuff to do.     * 循环等待材料来做。     */    while ( 1 )    {        /* Read all pending events.         * 读取全部待解决事件。         */        int ident;        int events;        struct android_poll_source* source;        /* If not animating, we will block forever waiting for events.         * 如果不是动画绘制中,我们将永远阻塞等待事件。         *         * If animating, we loop until all events are read,         * then continue to draw the next frame of animation.         * 如果动画绘制中,我们循环直到全部事件是读取,然后继续去画下一个动画的帧。         */                                        /* 零(0) - 立即返回,负壹(-1) - 无限等待 */        while ( ( ident = ALooper_pollAll( engine.animating ? 0 : -1,                                           NULL, /* 不返回发生事件的文件描述符 */        /* 在 android_native_app_glue.c 文件的 android_app_entry 函数体中         * 调用 ALooper_addFd 函数时设置为 ALOOPER_EVENT_INPUT - 文件描述符读操作有效 */                                           &events,                                           (void**)&source ) ) >= 0 )        {            /* Process this event.             * 处理这个事件。             */            if ( source != NULL )            {                /* 处理应用程序主线程的命令                 * 在 android_native_app_glue.c 文件的 android_app_entry 函数体中                 * 设置指向 process_cmd 或 process_input 函数。                 */                source->process( state, source );            }            /* If a sensor has data, process it now.             * 如果一个传感器有数据,马上处理它。             */            if ( ident == LOOPER_ID_USER )            {                if ( engine.accelerometerSensor != NULL )                {                    ASensorEvent event;                    while ( ASensorEventQueue_getEvents( engine.sensorEventQueue,                                                         &event,                                                         1 ) > 0 )                    {                        LOGI( "accelerometer: x=%f y=%f z=%f",                              event.acceleration.x, event.acceleration.y,                              event.acceleration.z );                    }                }            }            /* Check if we are exiting.             * 如果我们是正在退出,停止循环并返回。             */            if ( state->destroyRequested != 0 )            {                engine_term_display(&engine);                return;            }        }        if ( engine.animating )        {            /* Done with events; draw next animation frame.             * 事件完成;画下一个动画帧。             */            engine.state.angle += .01f; /* 0.1 递增变化 */            if ( engine.state.angle > 1 )            {                engine.state.angle = 0;            }            /* Drawing is throttled to the screen update rate,             * so there is no need to do timing here.             * 绘制是被屏幕更新率调节,所以这里是不需要做计时的。             */            engine_draw_frame( &engine );        }    }}//END_INCLUDE(all)

原创粉丝点击