2012-07-25 55 views
0

我正在使用c本機函數來更改java類的整數字段。基本上我想看看如何使用JNI實現引用調用。但是我收到錯誤「沒有爲本機找到實現」。任何人都可以幫助我解決這個問題。我是新來的android和java。以下是我寫的代碼。如果有人可以改變這個以滿足我想要的東西,我一定會感謝他的幫助。如何使用JNI來更改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 

請幫我

+0

需要注意的是日e NewGlobalRef調用是多餘的(您可以使用本地ref)和內存泄漏。 – technomage 2012-07-25 17:59:03

回答

1

你的C方法的名稱和簽名是錯誤的,名稱必須是Java_PackageName_ClassName_CfunctionName

如果你從一個名爲MyClass類調​​用它,並且它的包名是com.kpit.myfirstndkapp那麼你的方法必須被聲明爲

JNIEXPORT void JNICALL Java_com_kpit_myfirstndkapp_MyClass_callToChangeJNI(...) 
+0

是的,我意識到這一點,我能夠擺脫上述錯誤,但我沒有得到Java類字段a和b的價值。你能告訴我正確的代碼,我可以嘗試?非常感謝您的回覆。請幫幫我。我花在這個上的時間非常少 – user1497818 2012-07-25 12:21:50

+0

嘗試去除變量名稱周圍的這些空格:「a」和「b」應該是「a」和「b」。 – Dalmas 2012-07-25 12:29:16

+0

很多謝謝你的幫助。最後,我得到了解決方案,並將完整的代碼發佈到上述問題的解決方案中。此外它還提供瞭如何使用JNI訪問hava類的一些字段的票價構想 – user1497818 2012-07-26 06:53:54

0

最後,經過一些調試後,我得到了將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) 六月7日至26日:42:31.558:I/ActivityManager(93):顯示融爲一體。 android.launcher/com.android.launcher2.Launcher:+ 1m25s544ms

我非常感謝stackoverflow.com爲學習者提供這樣一個平臺,幫助像我這樣的

+0

如果你替換 jclass cls =(* env) - > GetObjectClass(env,obj);與\t jclass localRefCls =(* env) - > FindClass(env,「com/kpit myfirstndkapp/myclass」); myclass =(* env) - > NewGlobalRef(env,localRefCls); – user1497818 2012-07-26 10:32:09