网页
资讯
视频
图片
知道
文库
贴吧
地图
采购
进入贴吧
全吧搜索
吧内搜索
搜贴
搜人
进吧
搜标签
日
一
二
三
四
五
六
签到排名:今日本吧第
个签到,
本吧因你更精彩,明天继续来努力!
本吧签到人数:0
一键签到
成为超级会员,使用一键签到
一键签到
本月漏签
0
次!
0
成为超级会员,赠送8张补签卡
如何使用?
点击日历上漏签日期,即可进行
补签
。
连续签到:
天 累计签到:
天
0
超级会员单次开通12个月以上,赠送连续签到卡3张
使用连续签到卡
01月30日
漏签
0
天
c4droid吧
关注:
42,856
贴子:
262,798
看贴
图片
吧主推荐
游戏
1
2
3
4
5
下一页
尾页
102
回复贴,共
5
页
,跳到
页
确定
<<返回c4droid吧
>0< 加载中...
native activity 教程
只看楼主
收藏
回复
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
以下是本人刚整理的native activity 经验, 其中包括egl开窗,陀螺仪设备输入,以及多点触控输入的知识
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
首先,批评下c4droid自带的示例其实是从ndk开发包里"偸来的",居然用的是蛋疼的engine,state这类的struct封装,写得相当凌乱,毫无章法,这可能对大家,包括我的理解造成了不利影响。所以我会以极简的方法来描述如何使用native activity api写程序
一周休七日
外星人
9
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
插一下表示支持!
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
先看初始化指令,程序的主入口函数是android_main(struct android_app* app),是一个回传函数,app参数是java系统扔给我们的程序状态, 初始化指令共3条,如下:
app_dummy();
app->onAppCmd = on_app_cmd;
app->onInputEvent = on_input_event;
第一条指令:开窗的必要前提是glue功能没有被忽略,所以需要呼出一个dummy函数: app_dummy()。
第二条指令与第三条指令:
与sdl不同的是,native activity 采用的是回传函数(callback)方式
app参数需要你自定义两个成员回传函数,分别是 onAppCmd,与 onInputEvent,其中onAppCmd处理的是系统事件,onInputEvent处理的是输入事件,接下来我们分别看下这2个回传函数该怎么写
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
app->onAppCmd = on_app_cmd;
显而易见,我们首先要完成的是 app->onAppCmd,系统事件处理回传函数,也就是自己写的on_app_cmd函数,这个函数的原型是:
void on_app_cmd(struct android_app *app, int event_type)
其中1号参数的app和android_main中的app一样,是java系统扔给我们的程序状态,而2号参数event_type则是java系统扔给我们的当前事件。
至于怎么写,原理很简单,java系统每更新一次,都回扔给我们不同的event_type。所以和写其它的回传函数一样:针对不同event_type执行不同的指令
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
event_type,也就是事件类型,主要有4种,处理好了这4种一般来说就足够了:
1. APP_CMD_INIT_WINDOW: 窗口初始化
2. APP_CMD_TERM_WINDOW: 窗口关闭
3. APP_CMD_GAINED_FOCUS: 获得焦点
4.APP_CMD_LOST_FOCUS:失去焦点
其中必须要处理的只有窗口初始化,所以先从窗口初始化谈起
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
app->onAppCmd回传函数如果接收到的event_type的值为APP_CMD_INIT_WINDOW,我们就要打开一个可用于opengl渲染的窗口,而native activity开窗用的是egl api,我们可以把egl看成是glut或glfw之类的api,开窗过程如下:
attribs[11] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_NONE}
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(...);
eglChooseConfig(...);
eglGetConfigAttrib(...);
ANativeWindow_setBuffersGeometry(...);
sureface = eglCreateWindowSurface(...);
context=eglCreateWindowContext(...);
eglMakeCurrent(...);
过程如下:
1.把配置属性attribs填好,用eglGetDisplay()获得显示设备,并用eglInitialize()初始化显示设备。
2.以attribs为参考,用eglChooseConfig配置显示设备
3.用eglGetConfigAttrib()获得显示设备的原始图像编号,也就是EGL_NATIVE_VISUAL_ID
4.以获得的EGL_NATIVE_VISUAL_ID为参考,用ANativeWindow_setBuffersGeometry()设置安卓设备的显示缓冲平面(Buffers Geometry)
5.以刚配置好的显示设备为参考,用eglCreateWindowSurface创建一个egl窗口平面
6.以刚配置好的显示设备为参考,用eglCreateContext创建一个上下文
7.用eglMakeCurrent将先前显示设备,窗口平面,上下文设为当前egl的设备,平面,上下文
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
然后是窗口关闭,如下:
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(display, context);
eglDestroySurface(display, surface);
eglTerminate(display);
过程如下:
1.以EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT为参考,用eglMakeCurrent()使当前显示设备无效化
2.用eglDestroyContext()摧毁显示设备的上下文
3.用eglDestroySurface()摧毁显示设备的显示平面
4.用eglTerminate()中止显示设备
至于APP_CMD_GAINED_FOCUS与APP_CMD_LOST_FOCUS,由于和陀螺仪的配置有关,所以我们一会再谈
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
完成后的回传函数on_app_cmd()如下
void on_app_cmd(struct android_app *app, int event_type) /* app是java扔给我们的系统状态,event_type是java扔给我们的事件类型 */
{
switch (event_type) /* 我们根据java扔给我们的事件类型做出不同的反应 */
{
case APP_CMD_INIT_WINDOW: /* java扔给我们的事件类型是:初始化窗口 */
/* 在这里把7楼的初始化窗口代码写上 */
break;
case APP_CMD_TERM_WINDOW: /* java扔给我们的事件类型是:关闭窗口 */
/* 在这里把8楼的关闭窗口代码写上 */
break;
case APP_CMD_GAINED_FOCUS: /* java扔给我们的事件类型是:获得焦点 */
/* 讨论陀螺仪配置时,将在这里插入代码 */
break;
case APP_CMD_LOST_FOCUS: /* java扔给我们的事件类型是:失去焦点 */
/* 讨论陀螺仪配置时,将在这里插入代码 */
break;
}
}
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
完成了on_app_cmd()回传函数后,我们还要完成第二个自定义成员回传函数,也就是app->onInputEvent,这个函数处理的是键盘。。。
与多点触控事件。在这里只讨论多点触控事件。
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
与app->onAppCmd回传函数不同的是,app->onInputEvent的二号参数并不是整型事件id,而是自定义类型:AInputEvent,所以我们不能直接通过它的值来switch,而是要用AInputEvent_getType()口令获得输入事件类型。
多点触控的输入事件类型是AINPUT_EVENT_TYPE_MOTION,也就是说,如果我们将AInputEvent代入AInputEvent_getType()中去,如果返回的是AINPUT_EVENT_TYPE_MOTION,说明用户触碰了屏幕。
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
获得用户在屏幕上的触控坐标,要用到的函数有2个:
AMotionEvent_getX(AInputEvent *input_event, int index)
AMotionEvent_getY(AInputEvent *input_event, int index)
其中1号参数*input_event是输入事件,在回传函数中也就是java扔给我们的那个AInputEvent *。2号参数是触控序号,比如我用食指先碰到了屏幕,那么食指的触碰序号就固定为0,
我又将中指碰到了屏幕,那么此时中指的触控序号就固定为1,即使此时我将食指松开,中指的触控序号还是1,而0号便留空了,此时若将无名指碰到屏幕,则无名指的触碰序号为0。这就是多点触控的原理:“触碰者触碰后获得的触控序号是第一个可用的触控序号”
知道了这一点,我们就能通过AMotionEvent_getX()与AMotionEvent_getY()分别获得不同触控者的触碰坐标了。
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
现在来写 app->onInputEvent(),也就是on_input_event()函数,我们用触控序号0,1,2,分别检测三根手指的触碰坐标,函数如下:
int on_input_event(struct android_app *app, AInputEvent *input_event) /* app是java扔给我们的系统状态,input_event是java扔给我们的输入事件 */
{
if (AInputEvent_getType(input_event) == AINPUT_EVENT_TYPE_MOTION) /* 我们用AInputEvent_getType()得知输入事件是屏幕触碰 */
{
x0 = AMotionEvent_getX(input_event, 0); /* 将输入事件和触碰序号0,代入AMotionEvent_getX,得到0号手指的触碰横坐标 */
y0 = AMotionEvent_getY(input_event, 0); /* 将输入事件和触碰序号0,代入AMotionEvent_getX,得到0号手指的触碰纵坐标 */
x1 = AMotionEvent_getX(input_event, 1); /* 将输入事件和触碰序号1,代入AMotionEvent_getX,得到1号手指的触碰横坐标 */
y1 = AMotionEvent_getY(input_event, 1); /* 将输入事件和触碰序号1,代入AMotionEvent_getX,得到1号手指的触碰纵坐标 */
x2 = AMotionEvent_getX(input_event, 2); /* 将输入事件和触碰序号2,代入AMotionEvent_getX,得到2号手指的触碰横坐标 */
y2 = AMotionEvent_getY(input_event, 2); /* 将输入事件和触碰序号2,代入AMotionEvent_getX,得到2号手指的触碰纵坐标 */
}
return 0; /* 应当返回0,但如果认为input_event事件已经完全处理完毕的话,可以返回1 */
}
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
这样两个重要的回传函数全部都写好了, 只需要在android_main中简单的赋一下值:
app->onAppCmd = on_app_cmd;
app->onInputEvent = on_input_event;
android_main的骨架就已经完成了,如下:
void android_main(struct android_app* app)/* app是java扔给我们的系统状态 */
{
app_dummy();/* 确保glue的功能没有被忽略*/
app->onAppCmd = on_app_cmd;/* 将9楼完成的on_app_cmd回传函数赋值到app的 onAppCmd成员*/
app->onInputEvent = on_input_event;/* 将13楼完成的on_input_event回传函数赋值到app的 onInputEvent成员 */
android_app = app; /* 将app赋值到一个全局变量 (后面讨论)*/
/* 陀螺仪初始化代码(后面讨论) */
}
叜駣
小小白菜
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
开始处理,我们要处理的是名为source的android_poll_source结构指针,先前我们将source的内存位置代入了ALooper_pollAll,保存了当时的事件源,所以此时的source必然是一个有效指针或NULL,不会出现其它问题,如果事件源不为NULL,我们对其进行处理,struct android_poll_source有一个名为process的成员函数,只需要把java扔给我们的系统状态作为参数1,事件源指针source作为参数2代入即可,如下:
source->process(android_app, source); /* android_app 是我们在14楼保留的全局变量,口令是android_app = app; */
这样事件源的处理就完成了
登录百度账号
扫二维码下载贴吧客户端
下载贴吧APP
看高清直播、视频!
贴吧页面意见反馈
违规贴吧举报反馈通道
贴吧违规信息处理公示