Android JNI线程中回调Java方法

1,Android Jni线程中回调Java方法需要注意问题

  • 获取全局JavaVm

  • 通过JavaVm获取当前线程JNIEnv

  • 从UI线程传入当前线程的Object必须是全局变量

  • 通过JavaVm的AttachCurrentThread方法将当前线程附着到JavaVm

  • 在线程调用执行完之后,释放全局变量,释放当前线程JNIEnv

2,上代码(talk is easy,show me the code)

  • 在MainActivity中声明native方法:
public native void nativeUpdateProgress(OnProgressListener pl);
  • 在MainActivity中声明回调接口并初始化:
private OnProgressListener mPgl;

interface OnProgressListener{
    public void onProgress(int progress);
}

mPgl = new OnProgressListener() {
    @Override
    public void onProgress(int progress) {
        Log.d("NDKDemo","onProgress progress = "+progress);
    }
};
  • 在native-lib.cpp中声明需要的全局变量:
JavaVM *jvm = NULL;
bool mAttached = JNI_FALSE;
  • 在native-lib.cpp中声明nativeUpdateProgress对应的jni方法和线程调用的方法:
void* jniOnprogress(void *pgl){
    if(pgl == NULL){
        return NULL;
    }

    JNIEnv *pgl_thread_env = NULL;
    int env_state = jvm->GetEnv((void **)&pgl_thread_env,JNI_VERSION_1_6);

    /*if(pgl_thread_env == NULL){
        LOGD("pgl_thread_env init fail 1_6...");
        env_state = jvm->GetEnv((void **)&pgl_thread_env,JNI_VERSION_1_4);
    }*/

    //当前线程没有Attach
    if(env_state == JNI_EDETACHED){
        LOGD("cur thread not attach,do attach...");
        //TODO:attach cur thread
        if(jvm->AttachCurrentThread(&pgl_thread_env,NULL) != JNI_OK){
            return NULL;
        }
        mAttached = JNI_TRUE;
    }

    jobject callback = (jobject)pgl;
    //LOGD("cur thread not attach...env_state = %d",env_state);
    if(pgl_thread_env){
        jclass clz = pgl_thread_env->GetObjectClass(callback);
        if(clz == NULL){
            LOGD("cannot find cls...");
            jvm->DetachCurrentThread();
            return NULL;
        }
        jmethodID methodid = pgl_thread_env->GetMethodID(clz,"onProgress","(I)V");
        if(methodid == NULL){
            LOGD("cannot find method onProgress");
            jvm->DetachCurrentThread();
            return NULL;
        }
        pgl_thread_env->CallVoidMethod(callback,methodid,99);
    }

    //TODO:1,释放全局引用 2,释放当前thread 的env 3,将全局引用置空
    //释放全局引用
    pgl_thread_env->DeleteGlobalRef(callback);
    //释放当前thread 的env

    if(mAttached){
        jvm->DetachCurrentThread();
    }
    LOGD("after DetachCurrentThread...");
    pgl_thread_env = NULL;
    callback = NULL;
    return NULL;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_ndkdemo_MainActivity_nativeUpdateProgress(JNIEnv* env,jobject thiz,jobject pgl){

    env->GetJavaVM(&jvm);
    //这样的话会报错,因为当前在主线程,非全局的变量传到子线程可能会出问题
    //jobject callback = env->GetObjectClass(pgl);
    //生成一个全局的变量,传到子线程,才能保证正常的调用
    jobject callback = env->NewGlobalRef(pgl);

    pthread_t pgl_thread;
    pthread_create(&pgl_thread,NULL,jniOnprogress,callback);
}
  • 在MainActivity的OnCreate中调用nativeUpdateProgress方法:
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        
        mPgl = new OnProgressListener() {
            @Override
            public void onProgress(int progress) {
                Log.d("NDKDemo","onProgress progress = "+progress);
            }
        };
        nativeUpdateProgress(mPgl);
    }
  • 查看运行结果:

欧了。

你可能感兴趣的:(Android JNI线程中回调Java方法)