NativeActivity的胶水层android_native_app_glue详解和使用

本文详细解析了Android NativeActivity的胶水层android_native_app_glue,阐述了其如何实现ANativeActivity的事件回调,包括启动函数、事件处理、窗口生命周期等。并讨论了如何在不使用GLSurfaceView的情况下在native端处理OpenGL上下文,以及线程同步、事件处理和性能优化等方面的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    使用NativeActivity可以完全不使用java代码,全部使用native code来开发android程序。NativeActivity 为我们定制了native代码的各种接口回调,在ndk的samples里面,提供了一个例子如何使用NativeActivity。我们会发现,demo中使用了一个胶水层android_native_app_glue.h封装了native层面的ANativeActivity的事件回调。


    在native层面ANativeActivity对应的就是,java层面的NativeActivity。通过NativeActivity的java会代码会看到,ANativeActivity的回调函数都是在NativeActivity中被调用的。android_native_app_glue.c 主要做了以下几件事情。

  • 实现ANativeActivity启动函数,挂载ANativeActivity的事件回调函数。包括了事件处理,窗口生命周期等等。
  • 启动一个独立的线程,给使用者传递事件,和实现绘制。
  • 使用ALooper重新定义和实现了事件类型,让使用者实现回调处理。
    在整个android_native_app_glue代码的核心,就是如何使用ALooper串联起主线程事件,输入输出事件的。主线程事件,就是指在NativeActivity的回调事件。输入输出事件,就是input事件。


    简单介绍一个下ALooper,通过阅读java和c的定义代码。我的理解是,Looper可以把其它线程的事件放到队列里面,以后再一个线程里面独立处理。比如,OpenGL的调用就需要和Context在一个线程里面,就是典型的使用Looper的场景。我们从主线程拿到事件,然后在openGL的绘制线程里,处理looper收集的事件,这样事件处理和绘制就会在同一个线程里面了。


    从android/input.h和android/sensor.h我们可以了解到,要使用系统的输入输出和重力感应事件,我们需要传入Looper对象指针。在android/looper.h中可以了解到Looper的使用方式,每个线程可以附加一个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_native_app_glue 使用Looper的方式是非回调模式,回调函数传入NULL。就是Looper负责收集和释放事件,事件的处理需要自己调用。当然也有回调模式。ALooper_addFd 就是向Looper注册事件处理的方法。fd从何而来呢,如下:
    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];

就是利用管道的读写句柄来进行数据通信的。当ANativeActivity的事件在主线程触发的时候,向msgwrite写入了一个自定义的数据,然后调用ALooper_pollAll来处理Looper中事件,这时候利用msgwrite去读取写入的数据。由于是非回调Looper处理,所以android_native_app_glue使用一个结构在存放通用的事件处理,作为最后一个自定义参数传递给ALooper_addFd。如下:
/**
 * Data associated with an ALooper fd that will be returned as the "outData"
 * when that source has data ready.
 */
struct android_poll_source {
    // The identifier of this source.  May be LOOPER_ID_MAIN or
    // LOOPER_ID_INPUT.
    int32_t id;

    // The android_app this ident is associated with.
    struct android_app* app;

    // Function to call to perform the standard processing of data from
    // this source.
    void (*process)(struct android_app* app, struct android_poll_source* source);
};

我们继续查看process的实现和赋值的代码如下:
    android_app->cmdPollSource.id = LOOPER_ID_MAIN;
    android_app->cmdPollSource.app = android_app;
    android_app->cmdPollSource.process = process_cmd;
    android_app->inputPollSource.id = LOOPER_ID_INPUT;
    android_app->inputPollSource.app = android_app;
    android_app->inputPollSource.process = process_input;

static void process_input(struct android_app* app, struct android_poll_source* source) {
    AInputEvent* even
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值