android ndk jni层访问java对象小结
来源:互联网 发布:大学java 教不教线程 编辑:程序博客网 时间:2024/05/21 04:05
一.
android studio2.2.3采用ndk-build编译C++项目的流程:
1.创建的项目切换到project视图下,在main目录下新建一个jni目录
2.jni目录下新建一个Android.mk文件:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := testjni//需要生成的so库文件,可自定义LOCAL_C_INCLUDES+= $(LOCAL_PATH)SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)SRC_FILES := $(SRC_FILES:$(LOCAL_PATH)/%=%)LOCAL_SRC_FILES := $(SRC_FILES)#LOCAL_LDLIBS := -llog -landroidLOCAL_LDLIBS := -lloginclude $(BUILD_SHARED_LIBRARY)
3.build文件的配置:
apply plugin: 'com.android.application'android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.example.lxb.ndk_1" minSdkVersion 22 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk{ moduleName "testjni" abiFilters "armeabi"//这里可添加支持cpu架构 } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } externalNativeBuild { ndkBuild { path 'src/main/jni/Android.mk'//选用mk的方式编译项目,将mk文件选择link C++之后自动生成,也可手动配置 } }}dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.1' testCompile 'junit:junit:4.12'}
3.在gradle.properties 添加下面一行
# Project-wide Gradle settings.# IDE (e.g. Android Studio) users:# Gradle settings configured through the IDE *will override*# any settings specified in this file.# For more details on how to configure your build environment visit# http://www.gradle.org/docs/current/userguide/build_environment.html# Specifies the JVM arguments used for the daemon process.# The setting is particularly useful for tweaking memory settings.org.gradle.jvmargs=-Xmx1536m# When configured, Gradle will run in incubating parallel mode.# This option should only be used with decoupled projects. More details, visit# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects# org.gradle.parallel=trueandroid.useDeprecatedNdk=true//添加这一行
4.jni类:
package com.example.lxb.ndk_1.ndk;/** * Created by lxb on 2017/3/21. */public class HelloJni { static { System.loadLibrary("testjni"); } public static native String getJniString(); public native int operateArray(int[] a, int[] b); public native static String strConcat(String str1, String str2); public native int[] getIntArray(int size); public native void sortIntArray(int[] ints); public native void accessJavaMethod(); /** * 实例方法,在C++中调用 * * @return */ public String InstanceMethod() { return "JNI中通过方法id来调用java中的实例方法"; } /** * 静态方法,在C++中调用 * * java返回信息,在jni层打印出来 * @return */ public static String staticMethod() { return "JNI中通过方法id来调用静态方法"; } /** * jni层传入信息,在java层打印出来 * @param info */ public static void printInfo(String info){ System.out.println("51------------copy info from jni is: "+info); } /** * C++中测试调用带参数的方法 * * @param info * @return */ public String paramMethod(String info) { return info; } /** * c++能过原生方法调用带有多个不同类型的参数方法 * * @param a * @param str * @param array * @return */ public String MuitleParamMethod(int a, String str, int[] array) { int total = 0; for (int i = 0; i < array.length; i++) { total += array[i]; } String result = a + str + total; return result; } public native void callJavaObjMethod(); //public native void callJavaObjField(); public native void callJavaObjField(TestObj obj);}
5.测试用的java类:
package com.example.lxb.ndk_1.ndk;/** * Created by lxb on 2017/3/22. */public class TestObj { public String name ; private int age; public static int num = 21; public int sex; public TestObj(){ this.name = "liuhulai"; } 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; } /** * 实例方法,在C++中调用 * * @return */ public String InstanceMethod() { return "JNI中通过方法id来调用java中的实例方法"; } /** * 静态方法,在C++中调用 * * java返回信息,在jni层打印出来 * @return */ public static String staticMethod() { return "JNI中通过方法id来调用静态方法"; } @Override public String toString() { String sTmp = "名字:" + name + "年龄:" + age; return sTmp; }}
6.mainactivity:
package com.example.lxb.ndk_1;import android.app.Activity;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import com.example.lxb.ndk_1.ndk.HelloJni;import com.example.lxb.ndk_1.ndk.TestObj;/** * ndk-build编译方式 */public class MainActivity extends Activity { HelloJni jniObj; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); jniObj = new HelloJni(); } private void initView() { Button jniStr = (Button) findViewById(R.id.btn_jnistr); Button jniArray = (Button) findViewById(R.id.btn_jniarray); Button jniString = (Button) findViewById(R.id.btn_jnistring); Button jniReturnArray = (Button) findViewById(R.id.btn_jni_return_array); Button jniSortArray = (Button) findViewById(R.id.btn_jniarray_sort); Button jniAccessJavaField = (Button) findViewById(R.id.btn_jni_access_java_field); Button jnicalljavamethod = (Button) findViewById(R.id.btn_jni_call_java_method); Button jnicalljavaObj = (Button) findViewById(R.id.btn_jni_call_java_obj); Button jnicalljavaObjField = (Button) findViewById(R.id.btn_jni_obj_field); Button jnicalljavaObjMethod = (Button) findViewById(R.id.btn_jni_call_obj_medthod); EventClick eventClick = new EventClick(); jniStr.setOnClickListener(eventClick); jniArray.setOnClickListener(eventClick); jniString.setOnClickListener(eventClick); jniReturnArray.setOnClickListener(eventClick); jniSortArray.setOnClickListener(eventClick); jniAccessJavaField.setOnClickListener(eventClick); jnicalljavamethod.setOnClickListener(eventClick); jnicalljavaObj.setOnClickListener(eventClick); jnicalljavaObjField.setOnClickListener(eventClick); jnicalljavaObjMethod.setOnClickListener(eventClick); } private class EventClick implements View.OnClickListener { @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_jnistr: System.out.println("40------------------jnistr:" + jniObj.getJniString()); break; case R.id.btn_jniarray: int[] a = {1, 2, 3}; int[] b = {4, 5, 6}; System.out.println("40------------------jnistr:" + jniObj.operateArray(a, b)); break; case R.id.btn_jnistring: System.out.println("55-------------opertion string:" + jniObj.strConcat("liuhulai", "刘小兵")); break; case R.id.btn_jni_return_array: int[] jniarray = jniObj.getIntArray(10); System.out.println("65---------------get array from jni:"); for (int i = 0; i < jniarray.length; i++) { System.out.print(jniarray[i] + " "); } break; case R.id.btn_jniarray_sort: int[] sort = {9,0,7,6,8,5,3,4,2,1}; jniObj.sortIntArray(sort); System.out.println("排序后的数组为:"); for (int x:sort) { System.out.print(" "+x); } break; case R.id.btn_jni_access_java_field: break; case R.id.btn_jni_call_java_method: jniObj.accessJavaMethod(); break; case R.id.btn_jni_call_java_obj: break; case R.id.btn_jni_obj_field: TestObj obj = new TestObj(); jniObj.callJavaObjField(obj); System.out.println("114--------------jni修改java对象之后的值 为:"+obj.getName() + " : age: "+obj.getAge() + " 修改静态变量值为: "+TestObj.num); break; case R.id.btn_jni_call_obj_medthod: jniObj.callJavaObjMethod(); break; } } }}
7.cpp文件
//// Created by lxb on 2017/3/21.//#include<jni.h>#include<com_example_lxb_ndk_1_ndk_HelloJni.h>#include "string.h"#include "stdlib.h"#include "time.h"//定义随机数产生宏 表示产生0~x之间的随机数#define random(x) (rand()%x)#include<android/log.h> //引入Adnroid打印日志文件#define LOG "NDKTest" // 日志打印标识#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) // 对应Adnroid中DEBUGg模式,下类似#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__)#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)#ifndef NULL#define NULL ((void *) 0)#endifextern "C" { JNIEXPORT jstring JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_getJniString (JNIEnv *env, jclass) { char *result = "2017-----------this is jnistring C++"; jstring jstr = env->NewStringUTF(result); return jstr; } JNIEXPORT jint JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_operateArray(JNIEnv *env, jobject, jintArray arr1, jintArray arr2) { jint *carr; jint *carr2; jint i, sum = 0; carr = env->GetIntArrayElements(arr1, 0); carr2 = env->GetIntArrayElements(arr2, 0); if (carr == NULL || carr2 == NULL) { return 0; } for (i = 0; i < env->GetArrayLength(arr1); i++) { sum += carr[i] * carr2[i]; } env->ReleaseIntArrayElements(arr1, carr, 0); env->ReleaseIntArrayElements(arr2, carr2, 0); return sum; } JNIEXPORT jstring JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_strConcat (JNIEnv *env, jclass clazz, jstring str1, jstring str2) { //将jstring转换成const char*指针,使用const修饰符表示其内容不可被修改 //引用类型不能直接使用都需要进行一次转换,下面使用UTF方式进行转换 const char *c1 = env->GetStringUTFChars(str1, NULL); //将jstring 类型的str1转换为char* 指针类型 ,此时java层传过来的类型为jstring const char *c2 = env->GetStringUTFChars(str2, NULL); //计算新字符串的长度 int size = strlen(c1) + strlen(c2); //创建一个新的字符串,这里长度+1是为了使字符串有结尾标记'\0' char *n_char = new char[size + 1]; //利用C标准库提供的字符串操作方法对字符串进行连接,这里需要include"string.h"头文件 strcpy(n_char, c1); strcat(n_char, c2); //将生成的新字符串转换成UTF的jstring jstring rs = env->NewStringUTF(n_char); //发生转换 //删除刚刚分配的内存 避免引起内存泄漏 delete[] n_char; //通知JVM虚拟机Native代码不在持有字符串的引用,说明白点,就是告诉虚拟机我不使用它了,你可以回收了。 //因为在JVM中如果对象被引用,那么对象将不会被回收。 //这里为什么要传递jstring和生成的char*呢?是因为char*有可能是jstring的拷贝,如果是拷贝,那么char*就应该被删除。 env->ReleaseStringUTFChars(str1, c1); env->ReleaseStringUTFChars(str2, c2); return rs; } JNIEXPORT jintArray JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_getIntArray (JNIEnv *env, jobject jobj, jint size){ srand((int)time(0)); //用时间变量初始化随机数产生器 jint* rs = new jint[size]; //创建一个新jint* 指针类型 for (int i=0;i<size;i++) { rs[i] = random(100); //调用宏产生0~100的随机数 } jintArray array = env->NewIntArray(size); //通过JNIEnv的NewIntArray方法new一个jintArray对象,进行转换 env->SetIntArrayRegion(array,0,size,rs); //把产生的随机数值赋值给jintArray return array; } JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_sortIntArray (JNIEnv *env, jobject obj, jintArray array){ jsize size = env->GetArrayLength(array); //获取数组长度,其他数组也适用 //将数组转换为jni层的指针 jint* jints = env->GetIntArrayElements(array,NULL); //采用冒泡排序进行 for (int i = 0; i <size-1 ; ++i) { for (int j = 0; j <size-1-i ; ++j) { if(jints[j] < jints[j+1]) { int t=jints[j]; jints[j]=jints[j+1]; jints[j+1]=t; } } } //将排序结果更新到Java数组中,第三个参数等于0表明更新到原数组并释放所有元素 env->ReleaseIntArrayElements(array,jints,0); return; } JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_accessJavaMethod (JNIEnv *env, jobject obj){ jclass ClassJNI = env->FindClass("com/example/lxb/ndk_1/ndk/HelloJni"); //查找类名 jmethodID returnStringID = env->GetMethodID(ClassJNI, "InstanceMethod", "()Ljava/lang/String;"); //类名 方法名 形参类型,返回类型(java当中的返回类型) jstring jstr =(jstring)env->CallObjectMethod(obj,returnStringID); //调用带返回参数的java方法 const char *c_str = env->GetStringUTFChars(jstr, NULL); // 4. 将unicode编码的java字符串转换成C风格字符串 LOGI("java中的方法执行结果是:%s",c_str); //调用有输入参数与返回值的方法 jmethodID paramID = env->GetMethodID(ClassJNI, "paramMethod", "(Ljava/lang/String;)Ljava/lang/String;"); jstring param = env->NewStringUTF("这是java方法中需要的参数"); jstring jstr2 =(jstring)env->CallObjectMethod(obj, paramID, param); const char *c_str2 = env->GetStringUTFChars(jstr2, NULL); //将字符串进行转换到jni层可以访问的类型 LOGI("调用有输入参数与返回值的方法java中的方法执行结果是:%s",c_str2); //调用java中需要多个参数的方法 jmethodID muitleParamId = env->GetMethodID( ClassJNI, "MuitleParamMethod", "(ILjava/lang/String;[I)Ljava/lang/String;"); jint a=119; jstring tmp_jstr = env->NewStringUTF("liuzheyu"); //转换一个jni层的字符串 jintArray ret = env->NewIntArray(3); //转换一个jni层的 实例化一个一维数组 jint* buffer = new jint[1024]; //固定数组,测试用,注意别溢出 for (int i = 0; i < 3; i++) { buffer[i]=i; } env->SetIntArrayRegion(ret, 0, 3, buffer); //从NativeType类型(jint)数组中,拷贝0~y数据到jintArray对象中 jstring jstr3 =(jstring)env->CallObjectMethod(obj,muitleParamId,a,tmp_jstr,ret); //调用带返回参数的java方法 const char *c_str3 = env->GetStringUTFChars(jstr3, NULL); // 4. 将unicode编码的java字符串转换成C风格字符串 LOGI("调用java中多个参数的方法结果是:%s",c_str3); env->DeleteLocalRef(ret); //释放申请的jintArray,防止内存泄露 ,方式二:delete[] ret; env->DeleteLocalRef(tmp_jstr); env->DeleteLocalRef(jstr3); //访问java中的静态方法,打印java中静态方法返回的信息 jmethodID staticId = env->GetStaticMethodID(ClassJNI,"staticMethod","()Ljava/lang/String;"); jstring jstr_4 = (jstring) env->CallStaticObjectMethod(ClassJNI,staticId); const char * c_str4 = env->GetStringUTFChars(jstr_4,NULL); LOGI("访问java中的静态方法中结果是:%s",c_str4); //C++传入信息到java层打印出来,通过访问java的静态方法实现 jmethodID mid = env->GetStaticMethodID(ClassJNI, "printInfo", "(Ljava/lang/String;)V"); jstring jstr_44 = env->NewStringUTF("这条信息来自jni层"); //将“这条信息来自jni层” 转换为jstring类型 //3.调用printInfo方法并传递参数 //env->CallStaticVoidMethod(cls, mid, "JNI invoke Java Static Method");会报错,这种方法不允许 //所以String参数需要通过NewStringUTF生成jstring使用 env->CallStaticVoidMethod(ClassJNI, mid, jstr_44); } JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_callJavaObjMethod (JNIEnv *env, jobject cls){ jclass clazz = NULL; jobject jobj = NULL; jmethodID mid_construct = NULL; jmethodID mid_instance = NULL; jstring str_arg = NULL; // 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象 clazz = env->FindClass("com/example/lxb/ndk_1/ndk/TestObj"); if (clazz == NULL) { LOGI("找不到'com/example/lxb/ndk_1/ndk/TestObj'这个类"); return; } // 2、获取类的默认构造方法ID mid_construct = env->GetMethodID(clazz, "<init>","()V"); if (mid_construct == NULL) { LOGI("找不到默认的构造方法"); return; } // 3、查找实例方法的ID mid_instance = env->GetMethodID(clazz, "InstanceMethod", "()Ljava/lang/String;"); if (mid_instance == NULL) { return; } // 4、创建该类的实例 jobj = env->NewObject(clazz,mid_construct); if (jobj == NULL) { LOGI("在com/example/lxb/ndk_1/ndk/TestObj类中找不到InstanceMethod方法"); return; } // 5、调用对象的实例方法 str_arg = env->NewStringUTF("我是实例方法"); //env->CallVoidMethod(jobj,mid_instance,str_arg,200); jstring jstr =(jstring)env->CallObjectMethod(jobj,mid_instance); //调用带返回参数的java方法 const char *c_str = env->GetStringUTFChars(jstr, NULL); // 4. 将unicode编码的java字符串转换成C风格字符串 LOGI("258-------调java对象中的实例方法执行结果是:%s",c_str); // 删除局部引用 /* env->DeleteLocalRef(clazz); env->DeleteLocalRef(jobj); env->DeleteLocalRef(str_arg);*/ //测试调用java对象中的静态方法 jmethodID objStaticID = env->GetStaticMethodID(clazz,"staticMethod","()Ljava/lang/String;"); if(objStaticID == NULL){ LOGI("未找到'com/example/lxb/ndk_1/ndk/TestObj 里的staticMethod 方法"); return; } //jstring sStatic = env->NewStringUTF("我是静态方法的参数"); jstring jStaticStr = (jstring)env->CallStaticObjectMethod(clazz,objStaticID); const char *c_str2 = env->GetStringUTFChars(jStaticStr, NULL); // 4. 将unicode编码的java字符串转换成C风格字符串 LOGI("275-------调java对象中的静态方法执行结果是:%s",c_str2); env->DeleteLocalRef(clazz); env->DeleteLocalRef(jobj); env->DeleteLocalRef(str_arg); } JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_callJavaObjField(JNIEnv *env,jobject cls,jobject obj){ jclass clazz = NULL; jfieldID fid = NULL; jstring j_str = NULL; jstring j_newStr = NULL; const char *c_str = NULL; clazz = env->GetObjectClass(obj); // 1.查找需要调用的java类,找到之后会默认调用构造方法 if (clazz == NULL) { return; } fid = env->GetFieldID(clazz,"name", "Ljava/lang/String;"); // 2. 获取类实例变量name的属性ID if (fid == NULL) { return; } j_str = (jstring)env->GetObjectField(obj,fid); // 3. 获取实例变量name的值 c_str = env->GetStringUTFChars(j_str,NULL); // 4. 将unicode编码的java字符串转换成C风格字符串 if (c_str == NULL) { return; } LOGI("315--------获取到java对象的实例变量name = %s\n", c_str); env->ReleaseStringUTFChars(j_str, c_str); j_newStr = env->NewStringUTF("name from C String"); // 5. 修改实例变量str的值 if (j_newStr == NULL) { return; } env->SetObjectField(obj, fid, j_newStr); // 6.删除局部引用 /*env->DeleteLocalRef( clazz); env->DeleteLocalRef(j_str); env->DeleteLocalRef(j_newStr);*/ //获取静态变量 jfieldID staticFieldID = env->GetStaticFieldID(clazz,"num","I"); //1.获取静态变量名 if(staticFieldID == NULL){ LOGI("未发现类中的静态变量num"); return; } jint nNum = env->GetStaticIntField(clazz,staticFieldID); //2.获取变量值 LOGI("340------------静态变量num值为:%d\n",nNum); env->SetStaticIntField(clazz, staticFieldID, 27); // 4.修改静态变量num的值 // 删除属部引用 env->DeleteLocalRef(clazz); env->DeleteLocalRef(j_str); env->DeleteLocalRef(j_newStr); }}
生成头文件的方法:在adnroid studio 终端那一栏下使用javah试:
D:\demo\NDK_1\app\src\main>javah -d jni -classpath ./java com.example.lxb.ndk_1.ndk.HelloJni
8.测试结果:
Remote Branch :
Reconstruct Branch :
03-22 17:12:29.942 16717-16743/com.example.lxb.ndk_1 I/OpenGLRenderer: Initialized EGL, version 1.4
03-22 17:12:31.801 16717-16717/com.example.lxb.ndk_1 I/NDKTest: 315--------获取到java对象的实例变量name = liuhulai
03-22 17:12:31.801 16717-16717/com.example.lxb.ndk_1 I/NDKTest: 340------------静态变量num值为:21
03-22 17:12:31.801 16717-16717/com.example.lxb.ndk_1 I/System.out: 114--------------jni修改java对象之后的值 为:name from C String : age: 0 修改静态变量值为: 27
9.结果图:
布局文件:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/layout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_weight="1" android:id="@+id/btn_jnistr" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="获取jni字符串" /> <Button android:layout_weight="1" android:id="@+id/btn_jniarray" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="获取jni数组" /> <Button android:layout_weight="1" android:id="@+id/btn_jnistring" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="string类型交互" /> </LinearLayout> <LinearLayout android:id="@+id/layout2" android:layout_below="@+id/layout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_weight="1" android:id="@+id/btn_jni_return_array" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="获取jni返回数组" /> <Button android:layout_weight="1" android:id="@+id/btn_jniarray_sort" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="jni对java数组排序" /> </LinearLayout> <LinearLayout android:id="@+id/layout3" android:layout_below="@+id/layout2" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_weight="1" android:id="@+id/btn_jni_access_java_field" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="jni访问java属性" /> <Button android:layout_weight="1" android:id="@+id/btn_jni_call_java_method" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="jni调用java方法" /> <Button android:layout_weight="1" android:id="@+id/btn_jni_call_java_obj" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="jni调用java对象" /> </LinearLayout> <TextView android:id="@+id/txt_1" android:layout_below="@+id/layout3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="jni操作java任意对象:"/> <LinearLayout android:id="@+id/layout4" android:layout_below="@+id/txt_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_weight="1" android:id="@+id/btn_jni_obj_field" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="访问属性-静态,非静态" /> <Button android:layout_weight="1" android:id="@+id/btn_jni_call_obj_medthod" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="访问方法-静态,非静态" /> </LinearLayout></RelativeLayout>
- android ndk jni层访问java对象小结
- Android中关于JNI 的学习(三)在JNI层访问Java端对象
- Android中关于JNI 的学习(三)在JNI层访问Java端对象
- java 层调用Jni(Ndk) 持久化c c++ 对象
- Android NDK开发(二)——JNI访问和引用JAVA对象
- JNI NDK (1)---JNI NDK 的简单说明及从Java层中访问C/C++层
- Adnroid ndk 中jni访问java方法、对象、成员变量
- Android jni/ndk编程三:native访问java
- Android NDK之----- 在jni中创建java类对象
- Android NDK开发之Jni调用Java对象
- Android NDK开发之JNI调用Java对象
- Android NDK开发之Jni调用Java对象
- Android NDK开发之Jni调用Java对象
- Android NDK开发之JNI调用Java对象
- 转:Android NDK开发之Jni调用Java对象
- Android之HAL层编写JNI供Java接口访问
- Android NDK开发 。Java层与Jni层的数组传递(二)
- Android NDK 与 Java JNI
- Linq专题之提高编码效率—— 第一篇 Aggregate方法
- 前端学习之路JS(03)-对象
- Git常用命令大全
- Linq专题之提高编码效率—— 第二篇 神一样的匿名类型
- linux中ping命令的用法
- android ndk jni层访问java对象小结
- Android-nineoldandroids框架的使用
- Linq专题之提高编码效率—— 第三篇 你需要知道的枚举类
- ES6中的Promise
- Object类中的equals(Object obj) 、String类的equals(Object obj)和 操作符“==”的区别
- asp.net signalR 专题—— 第一篇 你需要好好掌握的实时通讯利器
- asp.net signalR 专题—— 第二篇 对PersistentConnection持久连接的快速讲解
- 乐观锁和悲观锁的实例讲解
- C++之explicit构造函数