• Android中关于JNI 的学习(三)在JNI层訪问Java端对象


    前面两篇文章简介了JNI层跟Java层的一些相应关系。包含方法名,数据类型和方法名称等。相信在理论层面,可以非常好地帮助我们去了解JNI在Native本地开发中的作用。对JNI的一些概念也有了一个初步的认识,因为表达能力或者理解还是有限。有些地方讲得不是非常清楚,假设各位朋友有认为云里雾里。欢迎大家留言一起学习。

    概念上的理解有助于我们更好地认识JNI,而一些实际点的样例则可以更好地帮我们从代码上去掌握并应用JNI。

    在第一篇文章。我们是从一个小样例来入门学习的,在当中,我们通过JNI层函数返回了一字符串。例如以下:

    JNIEXPORT jstring JNICALL Java_com_lms_jni_HwDemo_printHello
      (JNIEnv *e, jobject j)
    {
    	return (**e).NewStringUTF(e,"Hello from T");
    }
    

    这是一种最简单的情况,但很多其它时候。我们须要在JNI层获得Java对象,对其进行操作,最后将结果返回到Java端,所以这个时候我们就要利用到JNI函数定义的第二个參数 jobject了。

    上一篇文章,我们说过,JNIEnv *和jobejct參数都是JNI层方法加入的參数。关于JNIEnv*我们已经在前面的文章简介过,而jobject參数呢,则我们这一篇文章要操作到的參数了。

    对于本地方法。即在Java中定义的native方法,有静态(static)和非静态的方法,而我们知道,静态方法它是属于这个类的方法,对象不能操作它,而非静态方法则刚好相反,所以在JNI层的方法參数中:

    1)对于静态(static)方法。jobject參数表示的是相应Java类的引用。

    2)对于非静态方法。jobject表示的是相应Java对象的引用。

    这一点。应该不难理解。

    接下来。我们通过一个小Demo来学习怎么在JNI层操作Java端的对象,而且改变当中的值。

    首先,我们在Java类中定外一个static的变量testval,另一个方法changeTestVal()。用来改变testval的值,例如以下:

    public class ParamTransferTest {
    
    	public static int testval = 1;
    	
    	public native void changeTestVal();
    	...
    }

    当然,首先,第一步,我们要在C中实现其相应的函数了。例如以下:

    JNIEXPORT void JNICALL Java_com_lms_jni_ParamTransferTest_changeTestVal
      (JNIEnv * env, jobject obj){
    	jclass clazz = (*env)->GetObjectClass(env,obj);
    	jint val = (*env)->GetStaticIntField(env, clazz,
    						(*env)->GetStaticFieldID(env, clazz,"testval","I"));
    	LOGI("before change testval = %d", val);
    	val = val + 1;
    	LOGI("after change testval = %d", val);
    	(*env)->SetStaticIntField(env, clazz,(*env)->GetStaticFieldID(env, clazz,"testval","I"),val);
    }

    我们在相应的c文件里来实现这个native方法。由于实现的是非静态方法,所以jobject传过来的就是对该对象的引用,所以我们须要通过GetObjectClass方法来获得该对象相应的类。

    一般在JNI中,我们会利用FindClass和GetObjectClass两个方法来获得相应的类,并放到jclass类型的变量中去,只是在这里注意一点。用C实现和用C++实现的代码对于JNI的调用方法是不一样的。

    在前面文章中说过,C++对JNINativeInterface定义的方法进行了一层包装。所以其參数不再须要传递env进去,而C则是须要的,比方上面*env调用的方法,假设是用C++实现的话,那么是不再须要传递env參数进去的,即 GetObjectClass(jobject)就能够了。

    1)利用GetObjectClass方法获得jclass。

    2)调用GetStaticIntFieldID获得相应class相应的变量。即jclass中的类型为I(即int)的静态(static)变量 testval。

    3)调用GetStaticIntField获得相应变量的值 val。

    4)改变val 的值,在这里。我们进行加1操作。

    5)调用SetStaticIntField来设置相应变量的值。

    所以,在这里我们发现,Env事实上提供了非常多的方法,对于訪问对象变量值的,分为静态非静态的,基本上就是Get<Type>Field和GetStatic<Type>Field,

    而对应的。也有Set<Type>Field和SetStatic<Type>Field方法。

    而假设调用方法呢,就是利用Call<Type>Method和CallStatic<Type>Method方法了,这些大家能够自己去jni.h文件里自己看一下,就大概知道怎么做了。

    JNI层这边实现好了之后,我们利用ndk-build工具又一次生成一个so库,载入到Android中,在Activity中直接调用方法。例如以下:

    		TextView tvChangeTestVal = (TextView)findViewById(R.id.tvChangeTestVal);		
    		ParamTransferTest ptt = new ParamTransferTest();
    		ptt.changeTestVal();		
    		tvChangeTestVal.setText("" + ptt.testval);

    我们调用方法之后,在屏幕上将调用方法后的值,显示出来,结果应该是1+1=2,对吧。看以下结果:

    的确如我们所想像的,它的值已经变化成2了,对吧,说明我们的确是通过native方法在JNI层改变了其值。

    我们刚才也在JNI中加入了log,来展示其改变前后的值。例如以下:

    通过这样一个简单的小样例,相信大家应该就知道了怎么样在JNI层来操作Java端的数据了,对吧。

    结束。

  • 相关阅读:
    Macbook Catalina安装n2n问题汇总
    pyspider macbook安装问题汇总
    Windows——如何在文件资源管理器地址栏快速打开Vscode
    Tauri——如何创建一个tauri项目
    Electron——如何使用nodejs工作线程
    JavaScript——一个简单的队列Demo
    美国美元如何充值抖音、快手等直播平台
    怎么取消苹果手机自动续费_知乎会员怎样取消自动续费
    封装OCX
    Zabbix监控——Zabbix建立模板(templates)及监控项(item)
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7098410.html
Copyright © 2020-2023  润新知