Android - JNI 开发你所需要知道的基础,Android工程师面试题

本文详细介绍了Android JNI开发的基础知识,包括类型签名、对象创建、引用管理、线程相关操作,以及动态库加载、静态与动态注册方法。讲解了如何在JNI中调用Java方法、创建对象以及使用JNI_ONLoad,同时也探讨了使用makefile和cmake进行交叉编译的过程。内容适合Android工程师面试复习及日常开发使用。
摘要由CSDN通过智能技术生成

// 2. 获取成员变量 id
jfieldID strFieldId = env->GetFieldID(clazz,“testField”,“Ljava/lang/String;”);
// 3. 根据 id 获取值
jstring jstr = static_cast(env->GetObjectField(thiz, strFieldId));
const char* cStr = env->GetStringUTFChars(jstr,NULL);
LOGE(“获取 MainActivity 的 String field :%s”,cStr);

// 4. 修改 String
jstring newValue = env->NewStringUTF(“新的字符创”);
env-> SetObjectField(thiz,strFieldId,newValue);

// 5. 释放资源
env->ReleaseStringUTFChars(jstr,cStr);
env->DeleteLocalRef(newValue);
env->DeleteLocalRef(clazz);

// 获取静态变量
jfieldID staticIntFieldId = env->GetStaticFieldID(clazz,“staticField”,“I”);
jint staticJavaInt = env->GetStaticIntField(clazz,staticIntFieldId);

GetFieldID 和 GetStaticFieldID 需要三个参数:

  • jclass
  • filed name
  • 类型签名: JNI 使用 jvm 的类型签名
类型签名一览表
Type Signature Java Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
V void
L fully-qualified-class; fully-qualified-class
[type type[]
(arg-types) ret-type method type
  • 基本数据类型的比较好理解,不如要获取一个 int ,GetFieldID 需要传入签名就是 I;

  • 如果是一个类,比如 String,签名就是 L+全类名; :Ljava.lang.String;

  • 如果是一个 int array,就要写作 [I

  • 如果要获取一个方法,那么方法的签名是:(参数签名)返回值签名,参数如果是多个,中间不需要加间隔符,比如: | java 方法|JNI 签名| |–|--| |void f (int n); |(I)V| |void f (String s,int n); |(Ljava/lang/String;I)V| |long f (int n, String s, int[] arr); |(ILjava/lang/String;[I)J|

操作 method

操作 method 和 filed 非常相似,先获取 MethodID,然后对应的 CallXXXMethod 方法

Java层返回值 方法族 本地返回类型NativeType
void CallVoidMethod() (无)
引用类型 CallObjectMethod( ) jobect
boolean CallBooleanMethod ( ) jboolean
byte CallByteMethod( ) jbyte
char CallCharMethod( ) jchar
short CallShortMethod( ) jshort
int CallIntMethod( ) jint
long CallLongMethod() jlong
float CallFloatMethod() jfloat
double CallDoubleMethod() jdouble

在 java 中我们要想获取 MainActivity 的 className 会这样写:

this.getClass().getName()

可以看到需要先调用 getClass 方法获取 Class 对象,然后调用 Class 对象的 getName 方法,我们来看一下如何在 native 方法中调用:

extern “C” JNIEXPORT jstring JNICALL
Java_com_wangzhen_jnitutorial_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
std::string hello = “Hello from C++”;
// 1. 获取 thiz 的 class,也就是 java 中的 Class 信息
jclass thisclazz = env->GetObjectClass(thiz);
// 2. 根据 Class 获取 getClass 方法的 methodID,第三个参数是签名(params)return
jmethodID mid_getClass = env->GetMethodID(thisclazz, “getClass”, “()Ljava/lang/Class;”);
// 3. 执行 getClass 方法,获得 Class 对象
jobject clazz_instance = env->CallObjectMethod(thiz, mid_getClass);
// 4. 获取 Class 实例
jclass clazz = env->GetObjectClass(clazz_instance);
// 5. 根据 class 的 methodID
jmethodID mid_getName = env->GetMethodID(clazz, “getName”, “()Ljava/lang/String;”);
// 6. 调用 getName 方法
jstring name = static_cast(env->CallObjectMethod(clazz_instance, mid_getName));
LOGE(“class name:%s”, env->GetStringUTFChars(name, 0));

// 7. 释放资源
env->DeleteLocalRef(thisclazz);
env->DeleteLocalRef(clazz);
env->DeleteLocalRef(clazz_instance);
env->DeleteLocalRef(name);

return env->NewStringUTF(hello.c_str());
}

创建对象

首先定义一个 java 类:

public class Person {
private int age;
private String name;

public Person(int age, String name){
this.age = age;
this.name = name;
}

public void print(){
Log.e(“Person”,name + age + “岁了”);
}
}

然后我们再 JNI 中创建一个 Person 并调用它的 print 方法:

// 1. 获取 Class
jclass pClazz = env->FindClass(“com/wangzhen/jnitutorial/Person”);
// 2. 获取构造方法,方法名固定为
jmethodID constructID = env->GetMethodID(pClazz,"","(ILjava/lang/String;)V");
if(constructID == NULL){
return;
}
// 3. 创建一个 Pers

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值