Android NDK開發三:java和C\C++交互



1、定義native方法並加載動態鏈接庫:

public class HelloJni extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        TextView  tv = new TextView(this);
        tv.setText( stringFromJNI() );
        setContentView(tv);
    }


    public native String  stringFromJNI();


    public native String  unimplementedStringFromJNI();


    static {
        System.loadLibrary("hello-jni"); }
}

2、實現native方法:

#include <string.h>
#include <jni.h>
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !"); //in c
return
env->NewStringUTF("Hello from JNI !"); //in c++

}

若要定義靜態方法:

JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI
(JNIEnv * env, jclass clazz);

 

頭文件可以用javah工具生成:

進入命令行,切換到項目的bin目錄下的classes下面,執行 javah -classpath . -jni .類名。

或者:cd src目錄中,執行 javah .類名

 

3、數據

原始數據類型:

引用數據類型:

 

4、字符竄的操作:
1)新建字符串:

jstring javaString;

javaString = (*env)->NewStringUTF(env, "Hello World!");

2)把java string轉換成c string

const jbyte* str;
jboolean isCopy;
str = (*env)->GetStringUTFChars(env, javaString, &isCopy);
if (0 != str) {
printf("Java string: %s", str);
if (JNI_TRUE == isCopy) {
printf("C string is a copy of the Java string.");
} else {
printf("C string points to actual string.");
}
(*env)->ReleaseStringUTFChars(env, javaString, str);

5、數組的操作:

1)新建java數組:

jintArray javaArray;
javaArray = (*env)->NewIntArray(env, 10);
if (0 != javaArray) {
/* You can now use the array. */
}

2)獲取數組的值:

jint nativeArray[10];
//將java array 復制到 c array (
*env)->GetIntArrayRegion(env, javaArray, 0, 10, nativeArray);
//將 c array 還原城 java array
(*env)->SetIntArrayRegion(env, javaArray, 0, 10, nativeArray);

獲取數組指針:

jint* nativeDirectArray;
jboolean isCopy;
nativeDirectArray = (*env)->GetIntArrayElements(env, javaArray, &isCopy);
//...
(*env)->ReleaseIntArrayElements(env, javaArray, nativeDirectArray, 0);

6、C\C++獲取java成員變量

public class JavaClass {
/** Instance field */
private String instanceField = "Instance Field";
/** Static field */
private static String staticField = "Static Field";
...
}

1)獲取Field ID

jclass clazz;
clazz = (*env)->GetObjectClass(env, instance);

 

jfieldID instanceFieldId;
instanceFieldId = (*env)->GetFieldID(env, clazz,
"instanceField", "Ljava/lang/String;");

 

jfieldID staticFieldId;
staticFieldId = (*env)->GetStaticFieldID(env, clazz,
"staticField", "Ljava/lang/String;");

2)獲取Static Field

jstring staticField;
staticField = (*env)->GetStaticObjectField(env, clazz, staticFieldId);

 

7、C\C++調用java函數

public class JavaClass {
/**
* Instance method.
*/
private String instanceMethod() {
return "Instance Method";
}
/**
* Static method.
*/
private static String staticMethod() {
return "Static Method";
}
...
}

1)獲取Method ID:

成員函數:

jmethodID instanceMethodId;
instanceMethodId = (*env)->GetMethodID(env, clazz,
"instanceMethod", "()Ljava/lang/String;");

靜態函數:

jmethodID staticMethodId;
staticMethodId = (*env)->GetStaticMethodID(env, clazz,
"staticMethod", "()Ljava/lang/String;");

2)調用:

jstring instanceMethodResult;
instanceMethodResult = (*env)->CallStringMethod(env,
instance, instanceMethodId);

變量和函數的描述符:

javap工具可以提取從編譯過的class files 中提取這些描述符:

javap –classpath bin/classes –p –s com.example.hellojni.HelloJni

 

8、處理異常:

public class JavaClass {
/**
* Throwing method.
*/
private void throwingMethod() throws NullPointerException {
   throw new NullPointerException("Null pointer");
}
/**
* Access methods native method.
*/
private native void accessMethods();
}
jthrowable ex;
...
(*env)->CallVoidMethod(env, instance, throwingMethodId);
ex = (*env)->ExceptionOccurred(env);
if (0 != ex) {
(*env)->ExceptionClear(env);
/* Exception handler. */
}

從c\c++拋異常:

jclass clazz;
...
clazz = (*env)->FindClass(env, "java/lang/NullPointerException");
if (0 ! = clazz) {
(*env)->ThrowNew(env, clazz, "Exception message.");
}

9、本地和全局變量:

1)本地變量在函數結束時自動釋放內存:

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

2)新建全局變量:

jclass localClazz;
jclass globalClazz;
...
localClazz = (*env)->FindClass(env, "java/lang/String");
globalClazz = (*env)->NewGlobalRef(env, localClazz);
...
(*env)->DeleteLocalRef(env, localClazz);

3)釋放全局變量:

(*env)->DeleteGlobalRef(env, globalClazz);

4)弱全局引用:
弱全局引用可以被內存自動回收:

jclass weakGlobalClazz;
weakGlobalClazz = (*env)->NewWeakGlobalRef(env, localClazz);
if (JNI_FALSE == (*env)->IsSameObject(env, weakGlobalClazz, NULL)) {
/* Object is still live and can be used. */
} else {
/* Object is garbage collected and cannot be used. */
}
(*env)->DeleteWeakGlobalRef(env, weakGlobalClazz);

10、線程:

synchronized(obj) {
/* Synchronized thread-safe code block. */
}

 

if (JNI_OK == (*env)->MonitorEnter(env, obj)) {
/* Error handling. */
}
/* Synchronized thread-safe code block. */
if (JNI_OK == (*env)->MonitorExit(env, obj)) {
/* Error handling. */
}

native線程不能和java直接通信,必須先綁定到javaVM

JavaVM* cachedJvm;
...
JNIEnv* env;
...
/* Attach the current thread to virtual machine. */
(*cachedJvm)->AttachCurrentThread(cachedJvm, &env, NULL);
/* Thread can communicate with the Java application
using the JNIEnv interface. */
/* Detach the current thread from virtual machine. */
(*cachedJvm)->DetachCurrentThread(cachedJvm);

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM