Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android NDK開發常見錯誤

Android NDK開發常見錯誤

編輯:關於Android編程

錯誤一:

make: *** No rule to make target `/cygdrive/d/1-workspace/showmap-android-opengles/jni/showmap_opengles_OpenGLESRenderer.c', needed by `/cygdrive/d/1-workspace/showmap-android-opengles/obj/local/armeabi/objs/OpenGLESMap/showmap_opengles_OpenGLESRenderer.o'. Stop.

該錯誤是將showmap_opengles_OpenGLESRenderer.c改成showmap_opengles_OpenGLESRenderer.cpp後出現,當然android.mk文件中也作了相應修改

刪除 obj 文件夾,估計是有緩存信息導致去找showmap_opengles_OpenGLESRenderer.c而沒找到。

錯誤二:

 

 

 

一 javah引發的問題



BUG:
D/dalvikvm( 1704): Trying to load lib /data/data/com.ulang/lib/libulangaudio.so 0x41052a38
D/dalvikvm( 1704): Shared lib '/data/data/com.ulang/lib/libulangaudio.so' already loaded in same CL 0x41052a38
W/dalvikvm( 1704): No implementation found for native Lcom/ulang/AudioLib;. sayHelloEx ()Ljava/lang/String;
D/AndroidRuntime( 1704): Shutting down VM
W/dalvikvm( 1704): threadid=1: thread exiting with uncaught exception (group=0x409961f8)
E/AndroidRuntime( 1704): FATAL EXCEPTION: main
E/AndroidRuntime( 1704): java.lang.UnsatisfiedLinkError: sayHelloEx
E/AndroidRuntime( 1704): at com.ulang.AudioLib.sayHelloEx(Native Method)
E/AndroidRuntime( 1704): at com.ulang.One.onClick(One.java:76)
E/AndroidRuntime( 1704): at android.view.View.performClick(View.java:3480)
E/AndroidRuntime( 1704): at android.view.View$PerformClick.run(View.java:13983)
E/AndroidRuntime( 1704): at android.os.Handler.handleCallback(Handler.java:605)
E/AndroidRuntime( 1704): at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime( 1704): at android.os.Looper.loop(Looper.java:137)


發現第二個參數 javah生成為 jclass, 因此出錯 ,
要將其換成 jobject則可以.
Javah並不是所有情況都將第二項生成 jclass, 有時也是生成的jobject.
NE:要特別注意!
#define __cplusplus

#ifdef __cplusplus
extern C {
#endif
/*
* Class: com_ulang_AudioLib
* Method: sayHelloEx
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_ulang_AudioLib_sayHelloEx
(JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

 



  在實驗JNI接口調用的時候,發現時而成功,時而執行就異常,在logcat上就有提示:
  no implementation found in native ....
  後來搜索了一下網絡,發現出現這種情況有可能有幾種情況
  1.函數名字寫錯了
  2.確認在更改了接口函數的時候,要重新clean一下工程,再rebuild all。

  在確認以上兩點後,JNI接口調用的no implementation error沒有出現了。

 

 

 

(2)運行c++生成的.so庫,若報以下錯誤:(既找不到函數)

No implementation found for native Lcom/dgut/android/MainActivity;.stringFromJNI ()Ljava/lang/String;

java.lang.UnsatisfiedLinkError: stringFromJNI

at com.dgut.android.MainActivity.stringFromJNI(Native Method)

解決方法:

為供Java調用的c++函數前加入extern C 修飾,如:(NDK example裡面的cpp文件也是這麼聲明的,參考hello-gl2)

 

extern C {
	JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz );
}

JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )
{
    return env->NewStringUTF(Hello from JNI bear c++);
}
原因是:

被extern C修飾的變量和函數是按照C語言方式編譯和連接的。

首先看看C++中對類似C的函數是怎樣編譯的:作為一種面向對象的語言,C++支持函數重載,而過程式語言C則不支持。函數被C++編譯後在符號庫中的名字與C語言的不同。例如,假設某個函數的原型為:void foo( int x, int y );該函數被C編譯器編譯後在符號庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都采用了相同的機制,生成的新名字稱為“mangled name”)。_foo_int_int這樣的名字包含了函數名、函數參數數量及類型信息,C++就是靠這種機制來實現函數重載的。例如,在C++中,函數voidfoo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,後者為_foo_int_float。
同樣地,C++中的變量除支持局部變量外,還支持類成員變量和全局變量。用戶所編寫程序的類成員變量可能與全局變量同名,我們以.來區分。而本質上,編譯器在進行編譯時,與函數的處理相似,也為類中的變量取了一個獨一無二的名字,這個名字與用戶程序中同名的全局變量名字不同。

因此,若我們沒有使用extern C修飾函數,按照C語言方式編譯和連接,Jni調用將可能找不到該函數。

錯誤三:

 

【轉】 JNI調用錯誤: No implementation found for native

JNI 調用時,一直報 No implementation found for native

 

有一個可能是,如果調用的是C++的代碼,必須加extern C

 

【轉】 jni 調用c和c++的區別.

 

1、JNIEnv *env參數的使用

所有JNI接口的第一個參數是JNIEnv *env, 在C中,使用方法是

(*env)->NewStringUTF(env, Hello from JNI!);

但在C++中,其調用方法是

env->NewStringUTF(Hello from JNI!);

為什麼有這種區別呢,看看jni.h中關於JNIEnv的定義就可以知道了:

#if defined(__cplusplus)

typedef _JNIEnv JNIEnv;

#else

typedef const struct JNINativeInterface* JNIEnv;

#endif

可以看到,對於C和C++,定義有所不同,主要原因是C不支持類,所以采用了一種變通的方法。

 

2、接口找不到

在Java中調用JNI接口時,出現異常,察看日志,發現有如下錯誤:

WARN/dalvikvm(422): No implementation found for native Lcom/whty/wcity/HelixPlayer;.setDllPath (Ljava/lang/String;)V

檢查了幾遍代碼,Cpp中確實定義了這個接口,而且仔細對照了Java的包名、類名,確實沒有錯誤,那為什麼會出現這種問題呢。後來突然想到,JNI接口 都是以C的方式定義的,現在使用C++實現,函數定義前是否需要加上extern C呢?為此定義了一個頭文件,在CPP文件中include該頭文件,頭文件加上如下代碼片斷:

#ifdef __cplusplus

extern C {

#endif

#endif

...

#ifdef __cplusplus

}

再次嘗試,調用成功!


 


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved