Android开发,JNI,NDK,C++层操作java的对象实践
1.数组
在jni中调用数组
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testArr(JNIEnv *env, jobject thiz, jint a, jstring s,
jintArray ints, jobjectArray strings) {
int cnt = a;
LOGD("cnt == %d\n", cnt);
const char *test = env->GetStringUTFChars(s, NULL);
LOGD("------ %s\n", test);
//回收
env->ReleaseStringUTFChars(s, test);
}
运行下
遍历int数组在jni中
jni修改数组底层,JNI_OK标记
java层随之改变
2.引用数据类型数组
字符串类型数组在jni中
修改java层
jni代码
#include <jni.h>
#include <string>
#include <android/log.h>
#define TAG "testLog"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
//代码采用C语言编译
extern "C"
//关键字jni,
JNIEXPORT
//java的native方法的返回值
void
//关键字
JNICALL
//java包名, 类名,方法名
//jobject1是MainActivity的this实例
//一个是类调用,一个是对象调用,
Java_com_example_myapplication_MainActivity_test(JNIEnv *env, jobject jobject1) {
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_doubleFromJNI(JNIEnv *env, jobject thiz) {
jclass test = env->GetObjectClass(thiz);
// jfieldID num = env->GetFieldID(test, "num", "D");
//
// env->SetDoubleField(thiz,num, 444.5);
jfieldID num2 = env->GetFieldID(test, "num2", "D");
env->SetDoubleField(thiz, num2, 5555.5);
LOGD("SSSSSSSSSSSSSS %d\n", 1312);
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testAddNum(JNIEnv *env, jobject thiz) {
/*jclass jclass1 = env->GetObjectClass(thiz);
jmethodID add = env->GetMethodID(jclass1, "addNum", "(II)I");
int jint = env->CallIntMethod(thiz, add, 2, 3);
LOGD("============%d\n", jint);*/
jclass jclass1 = env->GetObjectClass(thiz);
jmethodID jmethodId = env->GetMethodID(jclass1, "getTestString",
"(Ljava/lang/String;I)Ljava/lang/String;");
jstring va = env->NewStringUTF("22222");
jstring rrr = (jstring) env->CallObjectMethod(thiz, jmethodId, va, 222);
const char *string = env->GetStringUTFChars(rrr, NULL);
LOGD("==============%s\n", string);
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testArr(JNIEnv *env, jobject thiz, jint a, jstring s,
jintArray ints, jobjectArray strings) {
int cnt = a;
LOGD("cnt == %d\n", cnt);
const char *test = env->GetStringUTFChars(s, NULL);
LOGD("------ %s\n", test);
//回收
env->ReleaseStringUTFChars(s, test);
//获取java传下来的数组
jint *jint1 = env->GetIntArrayElements(ints, NULL);
//计算长度
int len = env->GetArrayLength(ints);
for (int i = 0; i < len; ++i) {
LOGD("C++ %d\n", *(jint1 + i));
*(jint1 + i) = (i + 10111);
}
//释放素组内存,jni下面的修改传递给java层
env->ReleaseIntArrayElements(ints, jint1, JNI_OK);
//
int strslen = env->GetArrayLength(strings);
for (int i = 0; i < strslen; ++i) {
jstring jstring1 = (jstring) env->GetObjectArrayElement(strings, i);
const char *string = env->GetStringUTFChars(jstring1, NULL);
LOGD("C++============ %s\n", string);
//释放内存
env->ReleaseStringUTFChars(jstring1,string);
//修改java层
jstring updateValue = env->NewStringUTF("qiuqiuqiuqiuq");
env->SetObjectArrayElement(strings, i, updateValue);
jstring jstring12 = (jstring) env->GetObjectArrayElement(strings, i);
const char *string2 = env->GetStringUTFChars(jstring12, NULL);
LOGD("C++============2222 %s\n", string2);
//释放内存,jni函数结束会释放变量的内存
env->ReleaseStringUTFChars(jstring12,string2);
}
}
java代码
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
// System.loadLibrary("native-lib");
System.loadLibrary("native-lib");
}
private static final String TAG = "MainActivity";
private String test = "test";
public native String stringFromJNI();
public native void test();
private double num = 1;
private double num2 = 2;
public native void doubleFromJNI();
//jni调用它
public int addNum(int a, int b) {
Log.e(TAG, "addNum: ");
return a + b;
}
//
public native void testAddNum();
public String getTestString(String s, int a) {
Log.e(TAG, "getTestString: ");
return s;
}
public native void testArr(int a, String s, int[] ints, String[] strings);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
Log.e(TAG, "onCreate: ");
test();
Log.e(TAG, "onCreate: 修改前 " + num2);
doubleFromJNI();
Log.e(TAG, "onCreate: 修改后 " + num2);
testAddNum();
}
public void test1(View view) {
int[] ints = new int[]{1, 2, 3};
String[] strings = new String[]{"123", "1"};
testArr(111, "222", ints, strings);
for (int anInt : ints) {
Log.e(TAG, "test1: anInt" + anInt);
}
for (String string : strings) {
Log.e(TAG, "test1: string" + string);
}
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
}
3.java对象,jni层创建java对象
java
package com.example.myapplication;
import androidx.annotation.NonNull;
public class Test {
private static final String TAG = "Test";
public String name;
public int age;
public Test() {
}
public Test(String a, int b) {
this.name = a;
this.age = b;
}
public static String getTAG() {
return TAG;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Test{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
jni代码
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testObject(JNIEnv *env, jobject thiz,
jobject test,
jstring cstring) {
const char *string = env->GetStringUTFChars(cstring, NULL);
LOGD("string ============== %s\n", string);
//回收ziy
env->ReleaseStringUTFChars(cstring, string);
jclass jclass1 = env->FindClass("com/example/myapplication/Test");
//调用对象的toString
jmethodID toStringId = env->GetMethodID(jclass1, "toString", "()Ljava/lang/String;");
jstring jstring1 = (jstring) env->CallObjectMethod(test, toStringId);
const char *toStringJstring1 = env->GetStringUTFChars(jstring1, NULL);
LOGD("toStringJstring1 ==== %s\n", toStringJstring1)
}
测试代码
public void test2(View view) {
Test test = new Test();
test.name = "adasd";
test.age = 111;
testObject(test, "hello");
}
jni中调用对象的get,set方法
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testObject(JNIEnv *env, jobject thiz,
jobject test,
jstring cstring) {
const char *string = env->GetStringUTFChars(cstring, NULL);
LOGD("string ============== %s\n", string);
//回收ziy
env->ReleaseStringUTFChars(cstring, string);
jclass jclass1 = env->FindClass("com/example/myapplication/Test");
//调用对象的toString
jmethodID toStringId = env->GetMethodID(jclass1, "toString", "()Ljava/lang/String;");
jstring jstring1 = (jstring) env->CallObjectMethod(test, toStringId);
const char *toStringJstring1 = env->GetStringUTFChars(jstring1, NULL);
LOGD("toStringJstring1 ==== %s\n", toStringJstring1)
//释放内存
env->ReleaseStringUTFChars(jstring1, toStringJstring1);
env->DeleteLocalRef(jclass1);
jclass tesObj = env->FindClass("com/example/myapplication/Test");
jmethodID setName = env->GetMethodID(tesObj, "setName", "(Ljava/lang/String;)V");
jstring jstring2 = env->NewStringUTF("1123131");
//调用对象的set方法
env->CallVoidMethod(test, setName, jstring2);
//调用get方法
jclass tesObj1 = env->FindClass("com/example/myapplication/Test");
jmethodID getName = env->GetMethodID(tesObj, "getName", "()Ljava/lang/String;");
//调用对象的get方法
jstring jstring3 = (jstring) env->CallObjectMethod(test, getName);
const char *name = env->GetStringUTFChars(jstring3, NULL);
LOGD("get name ==== %s\n", name)
}
运行
可以看出get,set方法都被调用,并且get到我们设置的值
jni创建对象
java
public native void testCreateObj();
public void test3(View view) {
testCreateObj();
}
jni
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testCreateObj(JNIEnv *env, jobject thiz) {
jclass jclass1 = env->FindClass("com/example/myapplication/Test2");
jclass jclass2 = env->FindClass("com/example/myapplication/Test");
//分配对象,不会调用构造方法
jobject jobject1 = env->AllocObject(jclass1);
jobject jobject2 = env->AllocObject(jclass2);
//实例化对象
// env->NewObject(jclass1);
jmethodID jmethodId = env->GetMethodID(jclass1,"setTest",
"(Lcom/example/myapplication/Test;)V");
env->CallVoidMethod(jobject1,jmethodId,jobject2);
jmethodID setName = env->GetMethodID(jclass2, "setName", "(Ljava/lang/String;)V");
jstring jstring2 = env->NewStringUTF("2222222");
//调用对象的set方法
env->CallVoidMethod(jobject2, setName, jstring2);
}
运行在jni创建的对象,
4.全局对象引用
测试代码Test
package com.example.myapplication;
import android.util.Log;
import androidx.annotation.NonNull;
public class Test {
private static final String TAG = "Test";
public String name;
public int age;
public Test() {
Log.e(TAG, "Test: ");
}
public Test(int num) {
Log.e(TAG, "Test: " + num);
}
public Test(int num1, int num2) {
Log.e(TAG, "Test: " + num1 + num2);
}
public static void testStatic(String info) {
}
public Test(String a, int b) {
this.name = a;
this.age = b;
}
public static String getTAG() {
return TAG;
}
public String getName() {
return name;
}
public void setName(String name) {
Log.e(TAG, "setName: " + name);
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Test{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
MainActivity
public native void testGlobalReferences();
public native void deleteGlobalReferences();
@Override
protected void onDestroy() {
super.onDestroy();
deleteGlobalReferences();
}
public void test4(View view) {
testGlobalReferences();
}
public void test5(View view) {
deleteGlobalReferences();
}
jni调用java层的构造方法
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testGlobalReferences(JNIEnv *env, jobject thiz) {
if (!test) {
test = env->FindClass("com/example/myapplication/Test");
}
//init 构造方法。()调用无参构造方法
jmethodID jmethodId = env->GetMethodID(test, "<init>", "()V");
jobject jobject1 = env->NewObject(test, jmethodId);
//调用一个参数构造方法
jmethodID jmethodId2 = env->GetMethodID(test, "<init>", "(I)V");
jobject jobject2 = env->NewObject(test, jmethodId2, 1);
//调用两个参数构造方法
jmethodID jmethodId3 = env->GetMethodID(test, "<init>", "(II)V");
jobject jobject3 = env->NewObject(test, jmethodId3, 1, 2);
}
测试
局部引用和全局引用
//是局部变量,自动释放内存
jclass test = nullptr;
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_deleteGlobalReferences(JNIEnv *env, jobject thiz) {
if (!test) {
env->DeleteGlobalRef(test);
test = nullptr;
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testGlobalReferences(JNIEnv *env, jobject thiz) {
if (!test) {
// test = env->FindClass("com/example/myapplication/Test");
jclass jclass1 = env->FindClass("com/example/myapplication/Test");
//全局变量
test = (jclass) env->NewGlobalRef((jobject) jclass1);
env->DeleteLocalRef(jclass1);
}
//init 构造方法。()调用无参构造方法
jmethodID jmethodId = env->GetMethodID(test, "<init>", "()V");
jobject jobject1 = env->NewObject(test, jmethodId);
//调用一个参数构造方法
jmethodID jmethodId2 = env->GetMethodID(test, "<init>", "(I)V");
jobject jobject2 = env->NewObject(test, jmethodId2, 1);
//调用两个参数构造方法
jmethodID jmethodId3 = env->GetMethodID(test, "<init>", "(II)V");
jobject jobject3 = env->NewObject(test, jmethodId3, 1, 2);
}