【问题标题】:how to use the JNI to change the fields of a java class如何使用 JNI 更改 java 类的字段
【发布时间】:2012-07-23 18:16:42
【问题描述】:

我正在使用 c 本机函数来更改 java 类的整数字段。基本上我想看看如何使用 JNI 实现引用调用。但我收到错误“没有为本地找到实现”。谁能帮我解决这个问题。我是android和java的新手。以下是我编写的代码。如果有人可以改变这个来满足我想要的,我一定会感谢他的帮助。

java代码:

class myclass { 

    int a = 1;
    int b = 2;
    public native void callTochangeJNI();

    static {
        System.loadLibrary("sum_jni");
    }
}

public class sum extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sum);
        myclass myobject = new myclass(); 
        System.out.println("calling the jni native method");
        myobject.callTochangeJNI();
        System.out.println("returned from jni native method one");
        myobject.callTochangeJNI();
        System.out.format(" a = %d%n....", myobject.a);
        System.out.format("b =  %d%n...", myobject.b);
    }
}   

c 原生方法:

void Java_com_kpit_myfirstndkapp_sum_callTochangeJNI(JNIEnv* env, jobject obj )
{

    jfieldID fid;
    jmethodID mid;
    jclass myclass;

    printf(" Inside the JNI native method \n");

    jclass localRefCls = (*env)->FindClass(env, "java/lang/String");
    myclass = (*env)->NewGlobalRef(env, localRefCls);

    fid = (*env)->GetFieldID(env,myclass," a ","I");
    (*env)->SetIntField(env, obj ,fid,3);

    fid = (*env)->GetFieldID(env,myclass," b ","I");
    (*env)->SetIntField(env, obj ,fid,4);

}

下面是我得到的日志:

07-25 09:33:07.723: D/dalvikvm(573): Trying to load lib /data/da/com.kpit.myfirstndkapp /lib/libsum_jni.so 0x4129d7b8
07-25 09:33:07.723: D/dalvikvm(573): Added shared lib /data/data/com.kpit.myfirstndkapp/lib/libsum_jni.so 0x4129d7b8
07-25 09:33:07.723: D/dalvikvm(573): No JNI_OnLoad found in /data/data/com.kpit.myfirstndkapp/lib/libsum_jni.so 0x4129d7b8, skipping init
07-25 09:33:07.723: I/System.out(573): calling the jni native method
07-25 09:33:07.723: W/dalvikvm(573): No implementation found for native Lcom/kpit/myfirstndkapp/myclass;.callTochangeJNI ()V
07-25 09:33:07.733: I/dalvikvm(573): Wrote stack traces to '/data/anr/traces.txt'
07-25 09:33:07.804: D/AndroidRuntime(573): Shutting down VM
07-25 09:33:07.804: W/dalvikvm(573): threadid=1: thread exiting with uncaught exception (group=0x409c01f8)
07-25 09:33:07.854: E/AndroidRuntime(573): FATAL EXCEPTION: main
07-25 09:33:07.854: E/AndroidRuntime(573): java.lang.UnsatisfiedLinkError: callTochangeJNI
07-25 09:33:07.854: E/AndroidRuntime(573):  at com.kpit.myfirstndkapp.myclass.callTochangeJNI(Native Method)
07-25 09:33:07.854: E/AndroidRuntime(573):  at com.kpit.myfirstndkapp.sum.onCreate(sum.java:27)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.app.Activity.performCreate(Activity.java:4465)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.app.ActivityThread.access$600(ActivityThread.java:123)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.os.Handler.dispatchMessage(Handler.java:99)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.os.Looper.loop(Looper.java:137)
07-25 09:33:07.854: E/AndroidRuntime(573):  at android.app.ActivityThread.main(ActivityThread.java:4424)
07-25 09:33:07.854: E/AndroidRuntime(573):  at java.lang.reflect.Method.invokeNative(Native Method)
07-25 09:33:07.854: E/AndroidRuntime(573):  at java.lang.reflect.Method.invoke(Method.java:511)
07-25 09:33:07.854: E/AndroidRuntime(573):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
07-25 09:33:07.854: E/AndroidRuntime(573):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
07-25 09:33:07.854: E/AndroidRuntime(573):  at dalvik.system.NativeStart.main(Native Method)
07-25 09:33:08.234: I/dalvikvm(573): threadid=3: reacting to signal 3
07-25 09:33:08.264: I/dalvikvm(573): Wrote stack traces to '/data/anr/traces.txt'
07-25 09:33:08.554: I/dalvikvm(573): threadid=3: reacting to signal 3
07-25 09:33:08.623: I/dalvikvm(573): Wrote stack traces to '/data/anr/traces.txt'
07-25 09:38:07.994: I/Process(573): Sending signal. PID: 573 SIG: 9

请帮帮我

【问题讨论】:

  • 请注意,NewGlobalRef 调用是多余的(您可以使用本地 ref)和内存泄漏。

标签: android java-native-interface android-ndk-r7


【解决方案1】:

最后,经过一些调试,我得到了将 a 和 b 的值更改为新值的确切代码。这是正确的代码:

Java code:

package com.kpit.myfirstndkapp;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

class myclass { 
int a = 1;
int b = 2;

public native void callTochangeJNI();

static {
System.loadLibrary("sum_jni");
}
}

public class sum extends Activity {

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sum);

myclass myobject = new myclass(); 

System.out.println("calling the jni native method");

myobject.callTochangeJNI();
System.out.println("returned from jni native method one");

System.out.format(" a = %d%n....", myobject.a);
System.out.format("b =  %d%n...", myobject.b);

} }

C native library code:

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>

void Java_com_kpit_myfirstndkapp_myclass_callTochangeJNI(JNIEnv* env,
jobject obj)
{
jfieldID fid;
jmethodID mid;
jclass myclass;

printf(" Inside the JNI native method \n");
jclass cls = (*env)->GetObjectClass(env, obj);

fid = (*env)->GetFieldID(env,cls,"a","I");
(*env)->SetIntField(env, obj ,fid,3);

fid = (*env)->GetFieldID(env,cls,"b","I");
(*env)->SetIntField(env, obj ,fid,4);


}

This works and i get the below log on the screen:
07-26 06:42:30.838: I/System.out(551): calling the jni native method
07-26 06:42:30.859: I/System.out(551): returned from jni native method one
07-26 06:42:30.859: I/System.out(551):  a = 3
07-26 06:42:30.868: I/System.out(551): ....b =  4
07-26 06:42:31.179: I/Process(93): Sending signal. PID: 551 SIG: 3 
07-26 06:42:31.179: I/dalvikvm(551): threadid=3: reacting to signal 3
07-26 06:42:31.269: I/dalvikvm(551): Wrote stack traces to '/data/anr/traces.txt'
07-26 06:42:31.348: D/gralloc_goldfish(551): Emulator without GPU emulation detected.  
07-26 06:42:31.498: I/ActivityManager(93): Displayed com.kpit.myfirstndkapp/.sum:

+2s524ms(总+1m25s486ms) 07-26 06:42:31.558: I/ActivityManager(93): 显示 com.android.launcher/com.android.launcher2.Launcher: +1m25s544ms

非常感谢stackoverflow.com为像我这样的学习者提供了这样一个帮助平台

【讨论】:

  • 替换 jclass cls = (*env)->GetObjectClass(env, obj); with jclass localRefCls = (*env)->FindClass(env, "com/kpit myfirstndkapp/myclass"); myclass= (*env)->NewGlobalRef(env, localRefCls);
【解决方案2】:

你的C方法的名字和签名错误,名字必须是Java_PackageName_ClassName_CfunctionName

如果你从一个名为 MyClass 的类中调用它,并且它的包名是 com.kpit.myfirstndkapp,那么你的方法必须声明为

 JNIEXPORT void JNICALL Java_com_kpit_myfirstndkapp_MyClass_callToChangeJNI(...)

【讨论】:

  • 是的,我意识到了,我能够摆脱上述错误,但我没有得到 java 类字段 a 和 b 的值。你能告诉我我可以尝试的正确代码吗?非常感谢您的回复。请帮我。我花在这上面的时间很少
  • 尝试删除变量名周围的这些空格:" a " and " b " 应该是 "a" 和 "b"。
  • 非常感谢您的帮助。最后我得到了解决方案,我将完整的代码发布到上述问题的解决方案中。它还提供了如何使用 JNI 访问 hava 类的某些字段的基本思路
  • 不客气。如果对您有帮助,请接受答案(单击左侧的复选标记)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多