目录

  • 一、要介绍本篇博客的原因
  • 二、静态注册
    • 2.1 实现原理
    • 2.2 实现过程
    • 2.3 弊端
    • 2.4 示例
  • 三、动态注册
    • 3.1 实现原理
    • 3.2 实现过程
    • 3.3 优点
    • 3.4 示例

一、要介绍本篇博客的原因

前段时间学习OpenGL ES相关技术,下载了一个Github项目学习,项目地址在:https://github.com/githubhaohao/NDK_OpenGLES_3_0

项目的关键代码都是C++实现的,所以需要使用JNI技术。

我打开定义native方法的java类,如下所示:全部都是红色警告,


原因是,C++代码层没有对应的遵循特定JNI格式的JNI函数。

其实这个项目没有使用静态注册方法,而是使用了动态注册方法。下面我们分别来讲一下两种方式的区别。

二、静态注册

2.1 实现原理

根据函数名来建立java方法和JNI函数间的一一对应关系。

2.2 实现过程

  1. 编写.java代码;
  2. 编译.java代码,生成.class文件;
  3. 用过javah指令,利用生成的.class文件生成JNI.h文件;
  4. 生成后的JNI头文件中包含了Java函数在JNI层的声明;

可以参考下面几篇博客:

  • 【我的Android进阶之旅】Android Studio中JNI开发如何通过Extranal Tools 快速一键生成.h头文件
  • 【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法
  • 【我的Android进阶之旅】如果通过NDK编程,使用JNI来调用已经封装完毕的无法修改的so库(第三方)
  • 【我的Android进阶之旅】如何通过JNI来封装已有的C源码算法,然后让Java层调用C语言写的算法

2.3 弊端

  1. 书写很不方便,因为JNI层函数的名字必须遵循特定的格式,且名字特别长;
  2. 会导致程序员的工作量很大,因为必须为所有声明了native函数的java类编写JNI头文件;
  3. 程序运行效率低,因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时。

关于第1和第2点,随着Android Studio升级,现在可以直接写完java native方法 就可以使用快捷键【Alt + Enter】就会弹出提示提示【Create JNI function for xxx native method】,如下所示:

public class MyNativeRender {...  其他代码static {System.loadLibrary("native-render");}public native void native_Init();public native void native_UnInit();...  其他代码
}

比如我们生成一下,自动生成如下代码:

extern "C"
JNIEXPORT void JNICALL
Java_com_byteflow_app_MyNativeRender_native_1Init(JNIEnv *env, jobject thiz) {// TODO: implement native_Init()
}

再回到java层,就可以看到坐标有个C++的logo,点击即可跳转到对应的cpp代码的jni函数。

2.4 示例

目前我项目中还是使用的这种静态注册的方法。大家可以在下面的github查看

  • https://github.com/ouyangpeng/OpenGLESDemo
  1. java 层代码

java层代码编写native函数在com/oyp/openglesdemo/render/MyNativeRenderer.kt中,如下所示:

package com.oyp.openglesdemo.renderimport android.app.Activity
import android.content.res.AssetManager
import android.opengl.GLSurfaceView
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10class MyNativeRenderer(activity: Activity) : GLSurfaceView.Renderer, RenderAction {private var mActivity: Activity = activityvar mSampleType = 0init {System.loadLibrary("ouyangpeng-opengles-lib")}// 通用的private external fun nativeSurfaceCreate(assetManager: AssetManager)private external fun nativeSurfaceChange(width: Int, height: Int)private external fun nativeDrawFrame()private external fun nativeSetRenderType(sampleCategoryType: Int, renderSampleType: Int)private external fun nativeOnDestroy()// 特定的方法private external fun nativeSwitchBlendingMode()// 特定的方法private external fun nativeSetDelta(x: Float, y: Float)private external fun nativeSetMinFilter(filter: Int)private external fun nativeSetMagFilter(filter: Int)private external fun nativeSetImageData(format: Int,width: Int,height: Int,imageData: ByteArray?)private external fun nativeSetImageDataWithIndex(index: Int,format: Int,width: Int,height: Int,imageData: ByteArray?)private external fun nativeUpdateTransformMatrix(rotateX: Float,rotateY: Float,scaleX: Float,scaleY: Float)override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {val assetManager: AssetManager = mActivity.assetsnativeSurfaceCreate(assetManager)}override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {nativeSurfaceChange(width, height)}override fun onDrawFrame(gl: GL10) {nativeDrawFrame()}fun setRenderType(sampleCategoryType: Int, renderSampleType: Int) {if (sampleCategoryType == IMyNativeRendererType.SAMPLE_TYPE) {mSampleType = renderSampleType}nativeSetRenderType(sampleCategoryType, renderSampleType)}fun onDestroy() {nativeOnDestroy()}override fun switchBlendingMode() {nativeSwitchBlendingMode()}override fun setMinFilter(filter: Int) {nativeSetMinFilter(filter)}override fun setMagFilter(filter: Int) {nativeSetMagFilter(filter)}override fun setDelta(deltaX: Float, deltaY: Float) {nativeSetDelta(deltaX, deltaY)}override fun setImageData(format: Int,width: Int,height: Int,imageData: ByteArray) {nativeSetImageData(format, width, height, imageData)}override fun setImageDataWithIndex(index: Int,format: Int,width: Int,height: Int,imageData: ByteArray) {nativeSetImageDataWithIndex(index, format, width, height, imageData)}override fun updateTransformMatrix(rotateX: Float,rotateY: Float,scaleX: Float,scaleY: Float) {nativeUpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY)}
}


2. 对应的JNI方法

对应的JNI方法实现在app/src/main/cpp/jni/JniImpl.cpp文件中,如下所示:

//
// Created by OuyangPeng on 2021/11/26.
//
#include <jni.h>
#include <MyGLRenderContext.h>
#include <EGLRender.h>extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSurfaceCreate(JNIEnv *env, jobject thiz, jobject asset_manager) {MyGLRenderContext::GetInstance()->OnSurfaceCreated(env, asset_manager);
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSurfaceChange(JNIEnv *env, jobject thiz, jint width, jint height) {MyGLRenderContext::GetInstance()->OnSurfaceChanged(width, height);
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeDrawFrame(JNIEnv *env, jobject thiz) {MyGLRenderContext::GetInstance()->OnDrawFrame();
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetRenderType(JNIEnv *env, jobject thiz, jint sampleCategoryType, jint renderSampleType) {MyGLRenderContext::GetInstance()->SetRenderType(sampleCategoryType, renderSampleType);
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeOnDestroy(JNIEnv *env, jobject thiz) {MyGLRenderContext::DestroyInstance();
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSwitchBlendingMode(JNIEnv *env, jobject thiz) {MyGLRenderContext::GetInstance()->SwitchBlendingMode();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetDelta(JNIEnv *env, jobject thiz, jfloat x, jfloat y) {MyGLRenderContext::GetInstance()->SetDelta(x, y);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetMinFilter(JNIEnv *env, jobject thiz, jint filter) {MyGLRenderContext::GetInstance()->SetMinFilter(filter);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetMagFilter(JNIEnv *env, jobject thiz, jint filter) {MyGLRenderContext::GetInstance()->SetMagFilter(filter);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetImageData(JNIEnv *env, jobject thiz,jint format, jint width, jint height, jbyteArray imageData) {int len = env->GetArrayLength(imageData);u_int8_t *buf = new u_int8_t[len];env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte *>(buf));MyGLRenderContext::GetInstance()->SetImageData(format, width, height, buf);delete[]buf;env->DeleteLocalRef(imageData);
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetImageDataWithIndex(JNIEnv *env, jobject thiz,jint index, jint format, jint width, jint height, jbyteArray imageData) {int len = env->GetArrayLength(imageData);u_int8_t *buf = new u_int8_t[len];env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte *>(buf));MyGLRenderContext::GetInstance()->SetImageDataWithIndex(index, format, width, height, buf);delete[]buf;env->DeleteLocalRef(imageData);
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeUpdateTransformMatrix(JNIEnv *env, jobject thiz, jfloat rotateX,jfloat rotateY,jfloat scaleX,jfloat scaleY) {MyGLRenderContext::GetInstance()->UpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY);
}   EGL 渲染相关 extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderInit(JNIEnv *env, jobject thiz, jobject asset_manager) {EGLRender::GetInstance()->Init(env,asset_manager);
}extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderSetImageData(JNIEnv *env, jobject thiz, jbyteArray data, jint width, jint height) {int len = env->GetArrayLength (data);uint8_t* buf = new uint8_t[len];env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte*>(buf));EGLRender::GetInstance()->SetImageData(buf, width, height);delete[] buf;env->DeleteLocalRef(data);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderSetFragmentShaderType(JNIEnv *env, jobject thiz, jint param_type, jint fShaderType) {EGLRender::GetInstance()->SetFragmentShaderType(param_type, fShaderType);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderDraw(JNIEnv *env, jobject thiz) {EGLRender::GetInstance()->Draw();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderUnInit(JNIEnv *env, jobject thiz) {EGLRender::GetInstance()->UnInit();
}   EGL 渲染相关

实际上在Android Studio中,显示的效果还行,如下所示:

三、动态注册

由上面的介绍可以发现,通过Android Studio等IDE的功能越来越完善,关于JNI函数名很长的问题其实并不是瓶颈。

上面有提到一个弊端是程序运行效率低 :因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时。

应用层的Java类别通过VM而调用到native函数。一般是通过VM去寻找*.so里的native函数。
如果需要连续呼叫很多次,每次都需要寻找一遍,会多花许多时间。

此时,C组件开发者可以将本地函数向VM进行注册,以便能加快后续调用native函数的效率。

可以这么想象一下,假设VM内部一个native函数链表,初始时是空的,在未动态注册之前此native函数链表是空的,每次java调用native函数之前会首先在此链表中查找需要查找需要调用的native函数,如果找到就直接使用,如果未找到,得再通过载入的.so文件中的函数列表中去查找,且每次java调用native函数都是进行这样的流程,因此,效率就自然会下降。

为了克服这样现象,我们可以通过在.so文件载入初始化时,即JNI_OnLoad函数中,先行将native函数注册到VMnative函数链表中去,这样一来,后续每次java调用native函数时都会在VM中的native函数链表中找到对应的函数,从而加快速度.

注:在Android 源码开发环境下,大多采用动态注册native方法.

下面我们来介绍一下动态注册的方式。

3.1 实现原理

直接告诉native函数其在JNI中对应函数的指针;

3.2 实现过程

  1. 利用结构体JNINativeMethod保存Java Native函数和JNI函数的对应关系;
  2. 在一个JNINativeMethod数组中保存所有native函数和JNI函数的对应关系;
  3. Java中通过System.loadLibrary加载完JNI动态库之后,调用JNI_OnLoad函数,开始动态注册;
  4. JNI_OnLoad中会调用AndroidRuntime::registerNativeMethods函数进行函数注册;
  5. AndroidRuntime::registerNativeMethods中最终调用jni RegisterNativeMethods完成注册。

3.3 优点

克服了静态注册的弊端。

  1. RegisterNatives方法能帮助你把C/C++中的方法隐射到Java中的native方法,而无需遵循特定的方法命名格式。
  2. 更有效率去找到函数。
  3. 在执行期间进行抽换。

3.4 示例

我们就以 https://github.com/githubhaohao/NDK_OpenGLES_3_0的代码作为示例:

  • java层代码

代码定义在 app/src/main/java/com/byteflow/app/MyNativeRender.java 文件中

/**** Created by 公众号:字节流动 on 2021/3/12.* https://github.com/githubhaohao/NDK_OpenGLES_3_0* 最新文章首发于公众号:字节流动,有疑问或者技术交流可以添加微信 Byte-Flow ,领取视频教程, 拉你进技术交流群** */package com.byteflow.app;public class MyNativeRender {其他代码static {System.loadLibrary("native-render");}public native void native_Init();public native void native_UnInit();public native void native_SetParamsInt(int paramType, int value0, int value1);public native void native_SetParamsFloat(int paramType, float value0, float value1);public native void native_UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY);public native void native_SetImageData(int format, int width, int height, byte[] bytes);public native void native_SetImageDataWithIndex(int index, int format, int width, int height, byte[] bytes);public native void native_SetAudioData(short[] audioData);public native void native_OnSurfaceCreated();public native void native_OnSurfaceChanged(int width, int height);public native void native_OnDrawFrame();
}


2. Native层代码
代码定义在 app/src/main/cpp/JniImpl.cpp 文件中

  • 定义JNI NativeMethod的映射关系

g_RenderMethods[]和g_BgRenderMethods[]是2个<名称,函数指针>对照表,在程序执行时,可多次呼叫RegisterNativeMethods()函数来更换本地函数之指针,而达到弹性抽换本地函数之目的。

static JNINativeMethod g_RenderMethods[] = {{"native_Init",                      "()V",       (void *)(native_Init)},{"native_UnInit",                    "()V",       (void *)(native_UnInit)},{"native_SetImageData",              "(III[B)V",  (void *)(native_SetImageData)},{"native_SetImageDataWithIndex",     "(IIII[B)V", (void *)(native_SetImageDataWithIndex)},{"native_SetParamsInt",              "(III)V",    (void *)(native_SetParamsInt)},{"native_SetParamsFloat",            "(IFF)V",    (void *)(native_SetParamsFloat)},{"native_SetAudioData",              "([S)V",     (void *)(native_SetAudioData)},{"native_UpdateTransformMatrix",     "(FFFF)V",   (void *)(native_UpdateTransformMatrix)},{"native_OnSurfaceCreated",          "()V",       (void *)(native_OnSurfaceCreated)},{"native_OnSurfaceChanged",          "(II)V",     (void *)(native_OnSurfaceChanged)},{"native_OnDrawFrame",               "()V",       (void *)(native_OnDrawFrame)},
};static JNINativeMethod g_BgRenderMethods[] = {{"native_EglRenderInit",          "()V",       (void *)(native_EglRenderInit)},{"native_EglRenderSetImageData",  "([BII)V",   (void *)(native_EglRenderSetImageData)},{"native_EglRenderSetIntParams",  "(II)V",     (void *)(native_EglRenderSetIntParams)},{"native_EglRenderDraw",          "()V",       (void *)(native_EglRenderDraw)},{"native_EglRenderUnInit",        "()V",       (void *)(natuve_BgRenderUnInit)},
};

  • 定义要关联的对应Java类
#define NATIVE_RENDER_CLASS_NAME "com/byteflow/app/MyNativeRender"
#define NATIVE_BG_RENDER_CLASS_NAME "com/byteflow/app/egl/NativeEglRender"

  • 然后定义RegisterNativeMethods函数和UnregisterNativeMethods函数
static int RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodNum)
{LOGCATE("RegisterNativeMethods");jclass clazz = env->FindClass(className);if (clazz == NULL){LOGCATE("RegisterNativeMethods fail. clazz == NULL");return JNI_FALSE;}if (env->RegisterNatives(clazz, methods, methodNum) < 0){LOGCATE("RegisterNativeMethods fail");return JNI_FALSE;}return JNI_TRUE;
}static void UnregisterNativeMethods(JNIEnv *env, const char *className)
{LOGCATE("UnregisterNativeMethods");jclass clazz = env->FindClass(className);if (clazz == NULL){LOGCATE("UnregisterNativeMethods fail. clazz == NULL");return;}if (env != NULL){env->UnregisterNatives(clazz);}
}


  • JNI_OnLoad 函数和 JNI_OnUnload函数

JNI组件被成功加载和卸载时,会进行函数回调,
VM执行到System.loadLibrary(xxx)函数时,首先会去执行JNI组件中的JNI_OnLoad()函数,
而当VM释放该组件时会呼叫JNI_OnUnload()函数。

JNI_OnLoad()有两个重要的作用:

  1. 指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.6版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_6(该常量定义在jni.h中) 来告知VM
  2. 初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当。

JNI_OnUnload()的作用与JNI_OnLoad()对应,当VM释放JNI组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。

extern "C" jint JNI_OnLoad(JavaVM *jvm, void *p)
{LOGCATE("===== JNI_OnLoad =====");jint jniRet = JNI_ERR;JNIEnv *env = NULL;if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK){return jniRet;}jint regRet = RegisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME, g_RenderMethods,sizeof(g_RenderMethods) /sizeof(g_RenderMethods[0]));if (regRet != JNI_TRUE){return JNI_ERR;}regRet = RegisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME, g_BgRenderMethods,sizeof(g_BgRenderMethods) /sizeof(g_BgRenderMethods[0]));if (regRet != JNI_TRUE){return JNI_ERR;}return JNI_VERSION_1_6;
}extern "C" void JNI_OnUnload(JavaVM *jvm, void *p)
{JNIEnv *env = NULL;if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK){return;}UnregisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME);UnregisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME);
}

  • 完整代码
    完整代码如下所示:
//
// Created by ByteFlow on 2019/7/9.
//
#include "util/LogUtil.h"
#include <MyGLRenderContext.h>
#include <EGLRender.h>
#include "jni.h"#define NATIVE_RENDER_CLASS_NAME "com/byteflow/app/MyNativeRender"
#define NATIVE_BG_RENDER_CLASS_NAME "com/byteflow/app/egl/NativeEglRender"#ifdef __cplusplus
extern "C" {#endif
/** Class:     com_byteflow_app_MyNativeRender* Method:    native_Init* Signature: ()V*/
JNIEXPORT void JNICALL native_Init(JNIEnv *env, jobject instance)
{MyGLRenderContext::GetInstance();}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_UnInit* Signature: ()V*/
JNIEXPORT void JNICALL native_UnInit(JNIEnv *env, jobject instance)
{MyGLRenderContext::DestroyInstance();
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_SetImageData* Signature: (III[B)V*/
JNIEXPORT void JNICALL native_SetImageData
(JNIEnv *env, jobject instance, jint format, jint width, jint height, jbyteArray imageData)
{int len = env->GetArrayLength (imageData);uint8_t* buf = new uint8_t[len];env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte*>(buf));MyGLRenderContext::GetInstance()->SetImageData(format, width, height, buf);delete[] buf;env->DeleteLocalRef(imageData);
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_SetImageDataWithIndex* Signature: (IIII[B)V*/
JNIEXPORT void JNICALL native_SetImageDataWithIndex(JNIEnv *env, jobject instance, jint index, jint format, jint width, jint height, jbyteArray imageData)
{int len = env->GetArrayLength (imageData);uint8_t* buf = new uint8_t[len];env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte*>(buf));MyGLRenderContext::GetInstance()->SetImageDataWithIndex(index, format, width, height, buf);delete[] buf;env->DeleteLocalRef(imageData);
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_SetParamsInt* Signature: (III)V*/
JNIEXPORT void JNICALL native_SetParamsInt(JNIEnv *env, jobject instance, jint paramType, jint value0, jint value1)
{MyGLRenderContext::GetInstance()->SetParamsInt(paramType, value0, value1);
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_SetParamsFloat* Signature: (IFF)V*/
JNIEXPORT void JNICALL native_SetParamsFloat(JNIEnv *env, jobject instance, jint paramType, jfloat value0, jfloat value1)
{MyGLRenderContext::GetInstance()->SetParamsFloat(paramType, value0, value1);
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_SetAudioData* Signature: ([B)V*/
JNIEXPORT void JNICALL native_SetAudioData(JNIEnv *env, jobject instance, jshortArray data)
{int len = env->GetArrayLength(data);short *pShortBuf = new short[len];env->GetShortArrayRegion(data, 0, len, reinterpret_cast<jshort*>(pShortBuf));MyGLRenderContext::GetInstance()->SetParamsShortArr(pShortBuf, len);delete[] pShortBuf;env->DeleteLocalRef(data);
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_UpdateTransformMatrix* Signature: (FFFF)V*/
JNIEXPORT void JNICALL native_UpdateTransformMatrix(JNIEnv *env, jobject instance, jfloat rotateX, jfloat rotateY, jfloat scaleX, jfloat scaleY)
{MyGLRenderContext::GetInstance()->UpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY);
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_OnSurfaceCreated* Signature: ()V*/
JNIEXPORT void JNICALL native_OnSurfaceCreated(JNIEnv *env, jobject instance)
{MyGLRenderContext::GetInstance()->OnSurfaceCreated();
}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_OnSurfaceChanged* Signature: (II)V*/
JNIEXPORT void JNICALL native_OnSurfaceChanged
(JNIEnv *env, jobject instance, jint width, jint height)
{MyGLRenderContext::GetInstance()->OnSurfaceChanged(width, height);}/** Class:     com_byteflow_app_MyNativeRender* Method:    native_OnDrawFrame* Signature: ()V*/
JNIEXPORT void JNICALL native_OnDrawFrame(JNIEnv *env, jobject instance)
{MyGLRenderContext::GetInstance()->OnDrawFrame();}/** Class:     com_byteflow_app_egl_NativeBgRender* Method:    native_EglRenderInit* Signature: ()V*/
JNIEXPORT void JNICALL native_EglRenderInit(JNIEnv *env, jobject instance)
{EGLRender::GetInstance()->Init();}/** Class:     com_byteflow_app_egl_NativeBgRender* Method:    native_EglRenderSetImageData* Signature: ([BII)V*/
JNIEXPORT void JNICALL native_EglRenderSetImageData(JNIEnv *env, jobject instance, jbyteArray data, jint width, jint height)
{int len = env->GetArrayLength (data);uint8_t* buf = new uint8_t[len];env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte*>(buf));EGLRender::GetInstance()->SetImageData(buf, width, height);delete[] buf;env->DeleteLocalRef(data);}/** Class:     com_byteflow_app_egl_NativeBgRender* Method:    native_EglRenderSetIntParams* Signature: (II)V*/
JNIEXPORT void JNICALL native_EglRenderSetIntParams(JNIEnv *env, jobject instance, jint type, jint param)
{EGLRender::GetInstance()->SetIntParams(type, param);}/** Class:     com_byteflow_app_egl_NativeBgRender* Method:    native_EglRenderDraw* Signature: ()V*/
JNIEXPORT void JNICALL native_EglRenderDraw(JNIEnv *env, jobject instance)
{EGLRender::GetInstance()->Draw();
}/** Class:     com_byteflow_app_egl_NativeBgRender* Method:    natuve_BgRenderUnInit* Signature: ()V*/
JNIEXPORT void JNICALL natuve_BgRenderUnInit(JNIEnv *env, jobject instance)
{EGLRender::GetInstance()->UnInit();
}#ifdef __cplusplus
}
#endifstatic JNINativeMethod g_RenderMethods[] = {{"native_Init",                      "()V",       (void *)(native_Init)},{"native_UnInit",                    "()V",       (void *)(native_UnInit)},{"native_SetImageData",              "(III[B)V",  (void *)(native_SetImageData)},{"native_SetImageDataWithIndex",     "(IIII[B)V", (void *)(native_SetImageDataWithIndex)},{"native_SetParamsInt",              "(III)V",    (void *)(native_SetParamsInt)},{"native_SetParamsFloat",            "(IFF)V",    (void *)(native_SetParamsFloat)},{"native_SetAudioData",              "([S)V",     (void *)(native_SetAudioData)},{"native_UpdateTransformMatrix",     "(FFFF)V",   (void *)(native_UpdateTransformMatrix)},{"native_OnSurfaceCreated",          "()V",       (void *)(native_OnSurfaceCreated)},{"native_OnSurfaceChanged",          "(II)V",     (void *)(native_OnSurfaceChanged)},{"native_OnDrawFrame",               "()V",       (void *)(native_OnDrawFrame)},
};static JNINativeMethod g_BgRenderMethods[] = {{"native_EglRenderInit",          "()V",       (void *)(native_EglRenderInit)},{"native_EglRenderSetImageData",  "([BII)V",   (void *)(native_EglRenderSetImageData)},{"native_EglRenderSetIntParams",  "(II)V",     (void *)(native_EglRenderSetIntParams)},{"native_EglRenderDraw",          "()V",       (void *)(native_EglRenderDraw)},{"native_EglRenderUnInit",        "()V",       (void *)(natuve_BgRenderUnInit)},
};static int RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodNum)
{LOGCATE("RegisterNativeMethods");jclass clazz = env->FindClass(className);if (clazz == NULL){LOGCATE("RegisterNativeMethods fail. clazz == NULL");return JNI_FALSE;}if (env->RegisterNatives(clazz, methods, methodNum) < 0){LOGCATE("RegisterNativeMethods fail");return JNI_FALSE;}return JNI_TRUE;
}static void UnregisterNativeMethods(JNIEnv *env, const char *className)
{LOGCATE("UnregisterNativeMethods");jclass clazz = env->FindClass(className);if (clazz == NULL){LOGCATE("UnregisterNativeMethods fail. clazz == NULL");return;}if (env != NULL){env->UnregisterNatives(clazz);}
}// call this func when loading lib
extern "C" jint JNI_OnLoad(JavaVM *jvm, void *p)
{LOGCATE("===== JNI_OnLoad =====");jint jniRet = JNI_ERR;JNIEnv *env = NULL;if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK){return jniRet;}jint regRet = RegisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME, g_RenderMethods,sizeof(g_RenderMethods) /sizeof(g_RenderMethods[0]));if (regRet != JNI_TRUE){return JNI_ERR;}regRet = RegisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME, g_BgRenderMethods,sizeof(g_BgRenderMethods) /sizeof(g_BgRenderMethods[0]));if (regRet != JNI_TRUE){return JNI_ERR;}return JNI_VERSION_1_6;
}extern "C" void JNI_OnUnload(JavaVM *jvm, void *p)
{JNIEnv *env = NULL;if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK){return;}UnregisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME);UnregisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME);
}

【我的C语言学习进阶之旅】介绍一下NDK开发中关于JNI函数的两种注册方式:静态注册和动态注册相关推荐

  1. 【我的C/C++语言学习进阶之旅】NDK开发之解决错误:signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0xXXX

    一.错误描述 今天在使用C++实现一个OpenGL特效的时候,运行出错,如下所示: 错误描述为: signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr ...

  2. 【我的C语言学习进阶之旅】什么是.hpp文件?

    目录 一. `.hpp`文件是啥? 2.1 .hpp的疑问来源 2.2 什么是hpp文件? 2.2.1 以往套路 2.2.2 .hpp 新方式 2.3 使用`.hpp`文件有什么好处? 三.思考一下为 ...

  3. 【我的C语言学习进阶之旅】解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.

    一.问题描述 今天在Visual Studio 2019中写一段C语言的代码,发生生成错误.弹框如下: 点击[否(N)],提示如下: 错误具体信息为: 错误 C4996 'fscanf': This ...

  4. 【我的OpenGL学习进阶之旅】C++如何加载TGA文件?

    一.TGA文件相关介绍 通过前面的博客 [我的OpenGL学习进阶之旅]什么是TGA文件以及如何打开TGA文件? 地址:https://ouyangpeng.blog.csdn.net/article ...

  5. C语言字符串的两种定义方式

    C语言中 初始化一个字符串有两种定义方式: 第一种为 char str[] = "hello"; 或者 char str[] = {'h','e','l','l','o','\0' ...

  6. 【我的OpenGL学习进阶之旅】【持续更新】关于学习OpenGL的一些资料

    目录 一.相关书籍 OpenGL 方面 C方面 NDK 线性代数 二.相关博客 2.0 一些比较官方的链接 2.1 OpenGL着色器语言相关 2.2 [[yfan]](https://segment ...

  7. 【我的OpenGL学习进阶之旅】OpenGL ES 3.0新功能

    目录 1.1 纹理 1.2 着色器 1.3 几何形状 1.4 缓冲区对象 1.5 帧缓冲区 OpenGL ES 2.0 开创了手持设备可编程着色器的时代,在驱动大量设备的游戏.应用程序和用户接口中获得 ...

  8. 【我的OpenGL学习进阶之旅】着色器和程序(上)------着色器

    着色器和程序 一.前言 二.着色器和程序 2.1 创建和编译一个着色器 2.1.1 创建着色器 2.1.2 删除着色器 2.1.3 提供着色器源代码 2.1.4 编译色器 2.1.4 查询有关着色器对 ...

  9. 【我的OpenGL学习进阶之旅】介绍一下 绘制图元

    目录 一.绘制图元 1.1 `glDrawArrays` 1.1.1 `glDrawArrays`API说明 1.1.2 `glDrawArrays`API示例 1.2 `glDrawElements ...

最新文章

  1. c语言赋值x为字母,C语言算术、赋值、关系、逻辑运算详细剖析---
  2. oracle本地验证,Oracle 本地验证和密码文件
  3. ERP实施完了,为什么还要做MES?
  4. 解决sublime text无法安装插件问题
  5. php返回mysql错误语句_[已解决]php查询mysql返回了错误的结果
  6. [css] 怎么给手持设备添加特殊样式?
  7. java基础将字符串进行反转
  8. 如何将cad格式转化为qt可以识别的图像_看BIM技术如何计算土方工程量
  9. Linux设备驱动程序学习(2)-调试技术
  10. 软件测试人员应具备的素质
  11. java并发编程实战读书笔记4--生产者消费者模式和队列
  12. rs485接口上下拉_RS485上拉下拉电阻计算详解
  13. editormd文件上传
  14. Excel如何批量删除工作表中的所有空列
  15. eNSP下园区网综合实验分步配置(1)Eth-Trunk、Vlan、Trunk
  16. 使用Windows ADK 创建以U盘引导启动的Windows PE
  17. c语言钟表程序,制作一个电子时钟C语言版
  18. 机器学习实战——2.3 示例:手写识别系统
  19. Ai智能对话页面html,js人工智能对话框 - osc_q50is30g的个人空间 - OSCHINA - 中文开源技术交流社区...
  20. 几何画板与运筹学作图注记

热门文章

  1. colorkey口红怎么样_colorkey镜面唇釉怎么样 唇釉和口红有什么区别
  2. 第一课:数据库的基本操作(表的创建、删除、修改、重命名、主键、截断表)
  3. 大学期末考java编程题_大学慕课2020年Java程序设计期末考试大全答案
  4. 2015小米实习生笔试题1 求两个数的不同位的个数
  5. jquery实现抽奖小游戏
  6. Java 编程技巧之样板代码
  7. 空间解析几何:圆柱面一般式方程的推导——已知中轴线和半径
  8. 多线程系列学习:ABA问题
  9. sqlserver实现抽奖Demo
  10. excel pandas 画图_pandas 进行excel绘图