apiaccess.h
#include <jni.h>
#ifndef APIACCESS_H
#define APIACCESS_H
void init_data(JNIEnv* env);
void toast(char* msg);
#endif
您好-jni.c
#include <string.h>
#include <jni.h>
#include "apiaccess.h"
jstring javastr( JNIEnv* env, jobject thiz );
void connectfunc(JNIEnv* env){
JNINativeMethod methods[] =
{{ "stringFromJNI", "()Ljava/lang/String;", (void*)javastr}};
jclass clazz = (*env)->FindClass(env, "com/testndk/ndk/HelloJni");
int status = ((*env)->RegisterNatives(env, clazz, methods, 1));
}
jint JNI_OnLoad(JavaVM *vm, void *reserved){
// Get JNI Env for all function calls
JNIEnv* env = NULL;
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) return -1;
connectfunc(env);
init_data(env);
toast("Toast in JNI_OnLoad"); //error
//return jni version that we need. default valur is jni 1.1
return JNI_VERSION_1_6;
}
jstring javastr( JNIEnv* env, jobject thiz ){
toast("Toast in javastr");//no error
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
apiaccess.c
#include <jni.h>
JNIEnv* env = 0;
void init_data(JNIEnv* parenv){
env = parenv;
}
void toast(char* msg){
static jclass clazz = 0;
if(clazz==0) clazz = (*env)->FindClass(env, "com/testndk/ndk/HelloJni");
static jmethodID method = 0;
if(method==0) method = (*env)->GetStaticMethodID(env, clazz, "toast", "(Ljava/lang/String;)V");
(*env)->CallStaticVoidMethod(env,clazz,method,(*env)->NewStringUTF(env, msg));
}
HelloJni.java
package com.testndk.ndk;
import android.app.*;
import android.content.*;
import android.os.*;
import android.widget.*;
import android.util.*;
public class HelloJni extends Activity{
private static Context ctx;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
HelloJni.ctx = getApplicationContext();
TextView tv = new TextView(this);
tv.setText(stringFromJNI());
setContentView(tv);
}
public static void toast(String msg){
Toast.makeText(HelloJni.ctx, msg, Toast.LENGTH_SHORT).show();
}
public native String stringFromJNI();
static {
System.loadLibrary("hello-jni");
}
}
在javastr中调用toast工作正常。但是在JNI_OnLoad中,它崩溃了应用程序。 为什么我不能在JNI_OnLoad()中调用toast? 我提供了与此错误相关的所有代码。 Logcat输出:
I/Timeline( 1558): Timeline: Activity_launch_request id:com.testndk.ndk time:14821530
V/ApplicationPolicy( 999): isApplicationStateBlocked userId 0 pkgname com.testndk.ndk
D/ResourcesManager( 999): creating new AssetManager and set to /data/app/com.testndk.ndk-1/base.apk
I/ActivityManager( 999): START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.testndk.ndk/.HelloJni} from uid 10008 on display 0
I/ActivityManager( 999): Start proc com.testndk.ndk for activity com.testndk.ndk/.HelloJni: pid=28993 uid=10281 gids={50281, 9997} abi=armeabi
I/SurfaceFlinger( 246): id=6131 createSurf (1080x1920),2 flag=404, Starting com.testndk.ndk
D/ResourcesManager(28993): creating new AssetManager and set to /data/app/com.testndk.ndk-1/base.apk
E/AndroidRuntime(28993): Process: com.testndk.ndk, PID: 28993
E/AndroidRuntime(28993): at com.testndk.ndk.HelloJni.toast(HelloJni.java:25)
E/AndroidRuntime(28993): at com.testndk.ndk.HelloJni.<clinit>(HelloJni.java:30)
V/ApplicationPolicy( 999): isApplicationStateBlocked userId 0 pkgname com.testndk.ndk
W/ActivityManager( 999): Force finishing activity com.testndk.ndk/.HelloJni
D/CrashAnrDetector( 999): processName: com.testndk.ndk
D/CrashAnrDetector( 999): broadcastEvent : com.testndk.ndk data_app_crash
I/SurfaceFlinger( 246): id=6132 createSurf (49x49),1 flag=4, Application Error: com.testndk.ndk
W/ActivityManager( 999): Activity pause timeout for ActivityRecord{3a27a7c6 u0 com.testndk.ndk/.HelloJni t1692 f}
I/SurfaceFlinger( 246): id=6131 Removed Starting com.testndk.ndk (6/10)
I/SurfaceFlinger( 246): id=6131 Removed Starting com.testndk.ndk (-2/10)
I/ActivityManager( 999): Process com.testndk.ndk (pid 28993)(adj 9) has died(65,325)
I/SurfaceFlinger( 246): id=6132 Removed Application Error: com.testndk.ndk (7/9)
I/SurfaceFlinger( 246): id=6132 Removed Application Error: com.testndk.ndk (-2/9)
D/NetworkStatsFactory( 999): UpdateStatsForKnox
EDIT 我明白了问题所在。问题是在类加载时对System.LoadLibrary进行JNI_OnLoad调用和静态块调用。 所以ctx没有初始化并导致NullPointerException 我只是没有意识到静态块比构造函数
更早运行