2015-10-01 62 views
0

我有一個項目,我正在使用NativeActivity,以及android_native_app_glue文件連接到Java端。我需要通過Java訪問一些非NDK類,並想出如何從C調用Java,但是我遇到了相反的問題。當從Java到C的調用中,我得到「沒有找到實現......」,我已經檢查了這種調用的大部分缺陷,並相信一切都是正確的。這是Activity類。「找不到實現」使用NativeActivity

package com.JNITest; 

import android.app.NativeActivity; 
import android.util.Log; 

public class JniNativeActivity extends NativeActivity 
{ 
    private static String TAG = "JniNativeActivity"; 

    public static native void nativeJniCall(); 

    public JniNativeActivity() 
    { 
     super(); 
     Log.v(TAG, "Creating JniNativeActivity"); 
    } 

    public void testCall() 
    { 
     Log.v(TAG, "Calling native"); 
     nativeJniCall(); 
    } 
} 

由於這是用膠水代碼NativeActivity的沒有JNI_OnLoad調用時,入口點android_main(其中膠水代碼必須安裝在它自己的線程中運行)。

void android_main(struct android_app* state) 
{ 
    test_call(state->activity); 
    etc... 
} 

... 

void test_call(ANativeActivity *activity) 
{ 
    JNIEnv *jni; 

    activity->vm->AttachCurrentThread(&jni, NULL); 

    jclass activityClass=jni->GetObjectClass(activity->clazz); 
    jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V"); 

    jni->CallVoidMethod(activity->clazz, testCallId); 
} 

extern "C" 
{ 
    JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall(JNIEnv *, jclass) 
    { 
     LOGI("nativeJniCall"); 
    } 
} 

從logcat的

... 
waiting for debugger to settle... 
waiting for debugger to settle... 
debugger has settled (1388) 
Creating JniNativeActivity 
Creating: 0xb420b100 
Config: mcc=0 mnc=0 lang=en cnt=US orien=2 touch=3 dens=576 keys=2 nav=1 keysHid=1 navHid=0 sdk=22 size=2 long=1 modetype=1 modenight=1 
Start: 0xb420b100 
removeObsoleteFile: deleting file=161_task.xml 
Calling native 
No implementation found for void com.JNITest.JniNativeActivity.nativeJniCall() (tried Java_com_JNITest_JniNativeActivity_nativeJniCall and Java_com_JNITest_JniNativeActivity_nativeJniCall__) 
activityState=10 
Resume: 0xb420b100 
activityState=11 
Adding window Window{2b21e24c u0 com.JNITest/com.JNITest.JniNativeActivity} at 2 of 8 (before Window{3238fdec u0 Starting com.JNITest}) 
InputQueueCreated: 0xb420b100 -- 0xb420b880 
APP_CMD_INPUT_CHANGED 
Attaching input queue to looper 
NativeWindowCreated: 0xb420b100 -- 0xb417ae08 
APP_CMD_INIT_WINDOW 
Waiting for host to establish connection 
WindowFocusChanged: 0xb420b100 -- 1 
Accepting new connection from local client 
Accepted new client connection: PID = 3945, fd = 39 
Requesting connection from host 
Sending initiation request to host 
Accepting new connection from host service 
Accepted new host connection: fd = 40 
Connecting local socket 39 to host socket 40 
HostConnection::get() New Host Connection established 0xb4272e50, tid 3976 
Displayed com.JNITest/.JniNativeActivity: +5s618ms 

是什麼運行的事實意味着該庫被加載,它也是日誌

... 
=thread-created,id="9",group-id="i1"[New Thread 3958] 
=thread-created,id="10",group-id="i1"[New Thread 3959] 
=thread-created,id="11",group-id="i1"[New Thread 3960] 
Loaded 'D:\projects\JNITest\JNITest\JNITest.Android.NativeActivity\x86\Debug\libJNITest.so' 
=thread-created,id="12",group-id="i1"[New Thread 3976] 
[Switching to Thread 3976] 
=thread-created,id="13",group-id="i1"[New Thread 3975] 
Loaded 'gralloc.donatello.so' 
... 

我與JAVAH

驗證它的名字
extern "C" { 
#endif 
/* 
* Class:  com_JNITest_JniNativeActivity 
* Method: nativeJniCall 
* Signature:()V 
*/ 
JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall 
    (JNIEnv *, jclass); 

#ifdef __cplusplus 
} 
#endif 

我有還檢查庫實習醫生和功能是有

... 
     U glRotatef 
     U glShadeModel 
     U glTranslatef 
     U glVertexPointer 
     U glViewport 
00007004 D indices 
00004b70 T Java_com_JNITest_JniNativeActivity_nativeJniCall 
     U malloc 
     U memcpy 
     U memset 
     U pipe 
... 

我在另一個項目中有這個問題,並創建了一個測試應用程序(如上面的代碼是),所以它是不是有些隨機的唯一配置的問題。我在這一個有點損失,我假設它有NativeActivity和膠水代碼(可能是線程)的問題,但不知道如何解決它。任何幫助,將不勝感激。

回答

0

好吧,我發現了這個問題。在這種情況下,由於System.loadlibrary沒有與膠水代碼一起使用,因此標準查找機制不起作用。您必須手動調用RegisterNatives(來自有效的JNIEnv)。因此,對於這種情況下,你需要做到以下幾點:

void nativeJniCall(JNIEnv *, jclass) 
{ 
    LOGV("nativeJniCall"); 
} 

void android_main(struct android_app* state) 
{ 
    test_call(state->activity); 
    etc... 
} 

... 

void test_call(ANativeActivity *activity) 
{ 
    JNIEnv *jni; 

    activity->vm->AttachCurrentThread(&jni, NULL); 

    jclass activityClass=jni->GetObjectClass(activity->clazz); 
    jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V"); 

    JNINativeMethod methodTable[]= 
    { 
     {"nativeJniCall", "()V", (void *)nativeJniCall} 
    }; 

    int methodTableSize=sizeof(methodTable)/sizeof(methodTable[0]); 

    jni->RegisterNatives(activityClass, methodTable, methodTableSize); 

    jni->CallVoidMethod(activity->clazz, testCallId); 
} 

對於生產,你會緩存所有JCLASS/jmethoidIDs(記得用NewGlobalRef/DeleteGlobalRef),只有註冊的本地函數與類一次,但這作爲一個例子。希望它能夠節省一些時間。

相關問題