Android NDK之静态/动态注册Native方法

一、简介

关于NDK有两种方法注册:静态注册动态注册

  • 静态注册: 就是直接在Java文件里写个native方法 然后再c/c++文件中实现这个方法就行了;
  • 动态注册: 就是为了不要写很长的方法名,用JNI_OnLoad方法实现预注册,即当执行System.LoadLibrary()方法时候就把需要调用的方法给注册了,效率要高 Android就是采用此方法;

下面就以示例来说明静态注册动态注册以及C层调用Java层方法

二、代码实现

Github:NDKDemo

Java层Native方法定义

package com.cloudwise.ndk;
import android.util.Log;public class NDKUtil {// 静态注册Native方法public native static String stringFromJNI();// 静态注册Native方法public native static void setJNILogEnable(int type);// 动态注册Native方法public native static int getVersionCode();// 动态注册Native方法public native static String getVersion(int code);// 动态注册Native方法,并且C回调Java方法public native static void callJavaString();// 动态注册Native方法,并且C回调Java方法public native static void callJavaVoid();// C调用Java方法(带返回值)public static String getStringToC(String name){Log.e("CLOUDWISE", "name : " + name);return "C From Java";}// C调用Java方法(不带返回值)public static void getVoidToC(int id, String name){Log.e("CLOUDWISE", "id : " + id + " ---- name : " + name);}
}

C层代码

common.h

#ifndef NDKDEMO_COMMON_H
#define NDKDEMO_COMMON_H#ifdef __cplusplus
extern "C" {
#endif#define LOGOPEN 1 //日志开关,1为开,其它为关
#define LOG_TAG    "[CLOUDWISE-NDK]"
#if(LOGOPEN==1)#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)#define LOGD(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#else
#define LOGI(...) NULL#define LOGE(...) NULL#define LOGD(...) NULL
#endif#ifdef __cplusplus
}
#endif#endif //NDKDEMO_COMMON_H

native-lib.c

#include <jni.h>
#include <string.h>
#include <android/log.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include "common.h"static JavaVM *j_vm = NULL;
static jclass j_class = NULL;static jint debug = 1;/*** 静态注册的Native方法* @param env* @param arg* @return*/
JNIEXPORT jstring JNICALL Java_com_cloudwise_ndk_NDKUtil_stringFromJNI(JNIEnv *env,jclass arg) {jstring hello = "Hello ---- from ---- C";if(debug == 1){LOGE("stringFromJNI ---- Hello ---- from ---- C");}return (*env)->NewStringUTF(env, hello);
}/*** 静态注册的Native方法* @param env* @param arg* @param type*/
JNIEXPORT void JNICALL Java_com_cloudwise_ndk_NDKUtil_setJNILogEnable(JNIEnv *env,jclass arg, jint type){if(type == 1){debug = 1;} else {debug = 0;}
}/*** 动态注册的Native方法* @param env* @param arg* @return*/
JNIEXPORT jint JNICALL getVersionCode(JNIEnv *env, jclass arg){if(debug == 1){LOGE("getVersionCode ----------- 10");}return 10;
}/*** 动态注册的Native方法* @param env* @param arg* @param code* @return*/
JNIEXPORT jstring JNICALL getVersion(JNIEnv *env, jclass arg, jint code){if(debug == 1){LOGE("getVersion ----------- 1.2.6");}jstring ver = "1.2.6";return (*env)->NewStringUTF(env, ver);
}/*** C调用Java方法(带参数不带返回值)*/
void callVoidFromJava(){JNIEnv *env;(*j_vm)->AttachCurrentThread(j_vm, &env, NULL);jmethodID methodid = (*env)->GetStaticMethodID(env, j_class, "getVoidToC", "(ILjava/lang/String;)V");(*env)->CallStaticVoidMethod(env, j_class, methodid, 10, (*env)->NewStringUTF(env, "C-Name"));if(debug == 1) {LOGE("callVoidFromJava Java To C");}
}/*** C调用Java方法(带参数带返回值)*/
void callStringFromJava(){JNIEnv *env;(*j_vm)->AttachCurrentThread(j_vm, &env, NULL);jmethodID methodid = (*env)->GetStaticMethodID(env, j_class, "getStringToC", "(Ljava/lang/String;)Ljava/lang/String;");jstring str = (jstring)(*env)->CallStaticObjectMethod(env, j_class, methodid,(*env)->NewStringUTF(env, "C-Name"));char* java = (char*)(*env)->GetStringUTFChars(env, str, NULL);if(debug == 1) {LOGE("callStringFromJava Java To C : %s", java);}
}/*** 动态注册的Native方法,然后调用Java方法* @param env* @param arg*/
JNIEXPORT void JNICALL callJavaString(JNIEnv *env, jclass arg) {callStringFromJava();
}/*** 动态注册的Native方法,然后调用Java方法* @param env* @param arg*/
JNIEXPORT void JNICALL callJavaVoid(JNIEnv *env, jclass arg) {callVoidFromJava();
}static JNINativeMethod mMethods[] = {{"getVersionCode", "()I", (void*)getVersionCode},{"getVersion", "(I)Ljava/lang/String;", (void*)getVersion},{"callJavaString", "()V", (void*)callJavaString},{"callJavaVoid", "()V", (void*)callJavaVoid}
};static int registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods){jclass clazz;clazz = (*env)->FindClass(env, className);if(clazz == NULL){return -1;}j_class = (jclass)(*env) -> NewGlobalRef(env, (jobject)clazz);if((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0){return -1;}return 0;
}static int registerNative(JNIEnv* env){return registerNativeMethods(env, "com/cloudwise/ndk/NDKUtil", mMethods, sizeof(mMethods)/ sizeof(mMethods[0]));
}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){LOGE("JNI_OnLoad ------------------------------ ");JNIEnv* env = NULL;jint result = -1;/** JavaVM::GetEnv 原型为 jint (*GetEnv)(JavaVM*, void**, jint);* GetEnv()函数返回的  Jni 环境对每个线程来说是不同的,* 由于Dalvik虚拟机通常是Multi-threading的。每一个线程调用JNI_OnLoad()时,* 所用的JNI Env是不同的,因此我们必须在每次进入函数时都要通过vm->GetEnv重新获取*/if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK){return -1;}if(registerNative(env) != JNI_OK){return -1;}j_vm = vm;//cloudwise_init(1);result = JNI_VERSION_1_4;return result;
}

Java层调用代码

package com.cloudwise.ndk;import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import java.io.InputStream;public class CrashActivity extends AppCompatActivity implements View.OnClickListener {TextView txt;Button btn, btn_debug, btn_close, btn_ver_code, btn_ver, btn_logcat;// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_crash);// Example of a call to a native methodtxt = (TextView) findViewById(R.id.sample_text);btn = (Button)findViewById(R.id.btn);btn.setOnClickListener(this);btn_debug = (Button)findViewById(R.id.btn_debug);btn_debug.setOnClickListener(this);btn_close = (Button)findViewById(R.id.btn_close);btn_close.setOnClickListener(this);btn_ver = (Button)findViewById(R.id.btn_ver);btn_ver.setOnClickListener(this);btn_ver_code = (Button)findViewById(R.id.btn_ver_code);btn_ver_code.setOnClickListener(this);btn_logcat = (Button)findViewById(R.id.btn_string);btn_logcat.setOnClickListener(this);btn = (Button)findViewById(R.id.btn_void);btn.setOnClickListener(this);}private void btnClick(){txt.setText(NDKUtil.stringFromJNI());//Log.e("CLOUDWISE", "stringFromJNI-------");}private void btnDebug(){NDKUtil.setJNILogEnable(1);}private void btnClose(){NDKUtil.setJNILogEnable(0);}private void btnVer(){txt.setText(NDKUtil.getVersion(1));}private void btnVerCode(){txt.setText(NDKUtil.getVersionCode()+"");}private void btnString(){NDKUtil.callJavaString();}private void btnVoid(){NDKUtil.callJavaVoid();}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn:btnClick();break;case R.id.btn_debug:btnDebug();break;case R.id.btn_close:btnClose();break;case R.id.btn_ver:btnVer();break;case R.id.btn_ver_code:btnVerCode();break;case R.id.btn_string:btnString();break;case R.id.btn_void:btnVoid();break;}}
}

Java层布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:id="@+id/sample_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="" /><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="JNI调用"android:id="@+id/btn"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="VersionCode"android:id="@+id/btn_ver_code"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="Version"android:id="@+id/btn_ver"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="开启JNI日志"android:id="@+id/btn_debug"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="关闭JNI日志"android:id="@+id/btn_close"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="C调Java(带返回值)"android:id="@+id/btn_string"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="C调Java(不带返回值)"android:id="@+id/btn_void"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/></LinearLayout></ScrollView></LinearLayout>

布局界面

效果图

运行结果

[CLOUDWISE-NDK]: stringFromJNI ---- Hello ---- from ---- C
[CLOUDWISE-NDK]: getVersionCode ----------- 10
[CLOUDWISE-NDK]: getVersion ----------- 1.2.6
CLOUDWISE: name : C-Name
[CLOUDWISE-NDK]: callStringFromJava Java To C : C From Java
CLOUDWISE: id : 10 ---- name : C-Name
[CLOUDWISE-NDK]: callVoidFromJava Java To C

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446892.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

概率论 条件概率 全概率 贝叶斯公式

常用知识点 条件概率 1.P(B|A)1表示A发生的情况下B必然发生 A属于B 2.可列可加性 P(BUC|A)P(B|A)P(C|A) 3.P(B|A)的样本空间为A,A与B都发生了 大题解答思路 1.首先设取出一件商品为次品为事件A 2.写B1:甲生产,B2:乙生产 PB1…PB2… P(A|B1)…P(A|B2)… 3.写PAPB1*P(A|B1)……

C语言学习:%d、2d、02d、.2d的区别

%d&#xff1a;为普通的输出。 %2d&#xff1a;按宽度为2输出&#xff0c;右对齐方式输出。若不够两位&#xff0c;左边补空格。 %02d&#xff1a;同样宽度为2&#xff0c;右对齐方式。位数不够&#xff0c;左边补0。 %.2d&#xff1a;从执行效果来看&#xff0c;与%02d一样…

计算机系统基础 数据的表示和存储

数制和编码 1.信息的二进制编码 2.进制转换必须要知道: 1)使用哪一个进制(二,八…) 2)定点数还是浮点数(关于小数点的问题) 3)编码问题----原码,补码,反码,移码 3.进制转换 1)R进制转十进制(按权展开) ----R进制 ----八进制与十六进制 ----R转换为十进制 2)十进制转换为R…

物理 常见力与牛顿三定律

常用知识点 动量 dmvdmvdvm p-mv- f-dp-/dtma- 开普勒第三定律 r1^3__k只与恒星质量有关 T^2 总结 1.电梯匀速就相当于在地面,加速或减速就会有一个a 2.当合外力为0时,物体保持静止或匀速直线运动 3.力是改变物体运动状态的原因 4.重力在地球两极最大,赤道最小,随纬度…

Java命令:jmap — 打印指定进程的共享对象内存映射或堆内存细节

文章目录一、前言二、命令介绍三、使用实例1、jmap -heap [pid]2、jmap -histo[:live] [pid]3、jmap -histo[:live] [pid] |grep "[关键字1]\|[关键字2]"4、jmap -dump:live,formatb,filea.log [pid]四、总结一、前言 jdk安装后会自带一些小工具&#xff0c;jmap命令…

概率论 一维随机变量

随机变量 离散型随机变量:有限个或无限可列个 连续型随机变量 分布函数F(X) 范围是[a,b) 包含能取到a以及a之前的值的概率相加 分布律(概率分布) 1.所有概率相加为1 2.WX-1,计算出每一个对应的W,然后如果有相同的W就合并其概率,最后一一对应P(x)即可 概率密度函数(密度) …

JAVA牛客专项练习2020.12.31

1.使用迭代器的remove方法&#xff0c;可以边遍历边删除元素 2.线程 启动线程 new thread&#xff08;&#xff09;.start&#xff08;&#xff09; new thread&#xff08;new runnable&#xff08;&#xff09;&#xff09;.start&#xff08;&#xff09; 普通方法&#xf…

安卓牛客专项练习2020.12.31

1.窗口dialog或半透明 2.Pracelable性能比serializable高

安卓系统体系架构

1.大体:共有四层&#xff0c;系统应用层&#xff0c;JAVA API层&#xff0c;安卓系统运行层&#xff0c;Linux内核层 具体: 系统应用层&#xff08;System Apps&#xff09; Java API 框架层&#xff08;Java API Framework&#xff09; Android系统运行层&#xff08;包括Andr…

Java命令:jstack — 获取线程dump信息

目录一、命令介绍二、使用实例实例一&#xff1a;jstack查看输出实例二&#xff1a;jstack统计线程数实例三&#xff1a;jstack检测死锁实例四&#xff1a;jstack检测CPU高一、命令介绍 Usage:jstack [-l] <pid>(to connect to running process) //连接活动线程jstack …

Java多线程死锁例子

目录一、产生死锁的原因二、如何避免死锁一、产生死锁的原因 发生死锁的情况&#xff1a; 多个线程需要同时占用多个共享资源而发生需要互相死循环等待的情况&#xff0c;就是&#xff0c;两个线程互相等待着对象释放锁&#xff0c;一直这样僵持下去&#xff0c;所以导致了死锁…

安卓四大组件简介

安卓四大组件 Activity活动&#xff0c;Service服务&#xff0c;BroadcastRecevicer广播接受器&#xff0c;Content Provider内容提供者 Activity活动 所有程序的流程都运行在activity中 Service服务 只能后台运行&#xff0c;没有界面的长生命周期的代码 BroadcastRece…

WebLogic域的创建与发布

目录一、前言二、准备三、创建域步骤第一步&#xff1a;直接【回车】第二步&#xff1a;直接【回车】第三步&#xff1a;直接【回车】第四步&#xff1a;输入域名称后【回车】第五步&#xff1a;直接【回车】第六步&#xff1a;直接【回车】&#xff08;此步骤是提示域的存放目…

WebLogic启动失败:java.lang.AssertionError: Could not obtain the localhost address.

目录一、错误信息二、解决方案第一步&#xff1a;查看本机计算机名称第二步&#xff1a;编辑hosts文件一、错误信息 linux下启动WebLogic报如下错误&#xff1a; 二、解决方案 此错误多半是hosts文件不对导致的。 解决步骤如下&#xff1a; 第一步&#xff1a;查看本机计…

Windows查找JDK的路径

第一步&#xff1a;确定是否安装JDK 在控制台输入&#xff1a; java -version输出结果&#xff1a; 此时说明你电脑安装了JDK。 第二步&#xff1a;查找路径 然后在控制台输入&#xff1a; java -verbose输出结果&#xff1a; 从最后的jre目录可以找到相应的jdk目录。 …

安卓布局中xml文件属性和ID简介

编写xml属性 加载xml资源 当编译应用时&#xff0c;系统会将每个xml文件编译为view资源 属性 xml属性&#xff1a;特有属性&#xff0c;共有属性&#xff0c;其他属性&#xff08;布局参数&#xff09; ID ——在结构树中对view对象唯一标识 编译应用后&#xff0c;系统以…

Java监控工具VisualVM

目录一、简介二、内存分析1、Heap堆三、CPU分析四、线程分析一、简介 VisualVM 是一款免费的&#xff0c;集成了多个JDK命令行工具的可视化工具&#xff0c;它能为您提供强大的分析能力&#xff0c;对Java应用程序做 性能分析和调优 。这些功能包括 生成和分析海量数据、跟踪内…

C++数据类型

C 数据类型 |–基本数据类型: 整型 short短整型 2 int基本整型4 long长整型 8 浮点型 float单精度型 4 double双精度型 8 long double长双精度型 16 字符型 char 1 逻辑型 bool 1 空类型 void |–构造类型 数组类型 构造体类型 struct 共用体类型 union 枚举类型 enum 类类型…

Android Gradle 多渠道打包、动态配置AppName

目录一、简介二、Gradle多渠道打包1、普通做法2、Gradle多渠道打包一、简介 因为国内Android应用分发市场的现状&#xff0c;我们在发布APP时&#xff0c;一般需要生成多个渠道包&#xff0c;上传到不同的应用市场。这些渠道包需要包含不同的渠道信息&#xff0c;在APP和后台交…

Android Gradle 批量修改生成的apk文件名

目录一、简介二、代码实现1、 Gradle 3.0以下版本2、Gradle 3.0以上版本一、简介 平时开发都知道&#xff0c;我们要上线的时候需要在Android studio打包apk文件&#xff0c;可是默认的打包名是app-release.apk或者app-debug.apk这样的名字&#xff0c;太没有辨识度了。 下面…