本文共 8074 字,大约阅读时间需要 26 分钟。
首先更新一些知识点
1、根据jobject获取jclass(静态方法就不用这一步了)如:jclass clz = env->GetObjectClass(jobj);
获取jmethodid如: jmethodid jmid = env->GetMethodID(clz, "onError", "(ILjava/lang/String;)V")
3、调用方法如: jenv->CallVoidMethod(jobj, jmid, code, jmsg)
由于JniEnv是线程相关的,所以子线程中不能使用创建线程的JniEnv;而 JVM是进程相关的,所以可以通过JVM来获取当前线程的JniEnv,然后就可以 调用Java的方法了。
1、获取JVM对象: JNI_OnLoad(JavaVM* vm,void* reserved)
2、通过JVM获取JniEnv: JNIEnv *env; jvm->AttachCurrentThread(&env, 0); /* call Java Methoid */ jvm->DetachCurrentThread();
接下来上代码
xml
mainactivity
package com.example.jnithread;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;public class MainActivity extends AppCompatActivity { ThreadDemo mThreadDemo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mThreadDemo = new ThreadDemo(); mThreadDemo.setmOnErrorListener(new ThreadDemo.OnErrorListener() { @Override public void onError(int code, String msg) { Log.i("godv", "code :" + code + "msg:" + msg); } }); } public void run(View view) { mThreadDemo.startThread(); } public void buy(View view) { mThreadDemo.startBuyThread(); } public void callJavaMain(View view) { mThreadDemo.cCallBackJava(); }}
ThreadDemo
package com.example.jnithread;public class ThreadDemo { static { System.loadLibrary("native-lib"); } public native void startThread(); public native void startBuyThread(); public native void cCallBackJava(); // public void onError(int code, String msg) { if (mOnErrorListener != null) { mOnErrorListener.onError(code, msg); } } public interface OnErrorListener { void onError(int code, String msg); } private OnErrorListener mOnErrorListener; public void setmOnErrorListener(OnErrorListener mOnErrorListener) { this.mOnErrorListener = mOnErrorListener; }}
nativelib-cpp
#include#include #include "GodvLog.h"//线程的头文件#include "pthread.h"//线程的变量pthread_t thread;//线程的回调 也就是真正执行的函数void *mycallBack(void *data) { LOGD("GODV create thread in c++"); //销毁线程 pthread_exit(&thread);}//普通线程extern "C"JNIEXPORT void JNICALLJava_com_example_jnithread_ThreadDemo_startThread(JNIEnv *env, jobject thiz) { //创建线程的api pthread_create(&thread, NULL, mycallBack, NULL);}//队列的头文件#include "queue"//sleep的头文件#include "unistd.h"//消费者线程pthread_t buy;//消费者线程pthread_t sell;//线程锁pthread_mutex_t mutex;//线程信号pthread_cond_t cond;bool tag = true;//创建队列std::queue queue;void *buyCallBack(void *data) { while (tag) { //线程锁 pthread_mutex_lock(&mutex); if (queue.size() > 0) { queue.pop(); LOGD("消费者消费了一个产品,目前产品总数为:%d", queue.size()); } else { LOGD("消费者正在等待。。。"); //线程等待 同时释放线程锁 pthread_cond_wait(&cond, &mutex); } //线程解锁 pthread_mutex_unlock(&mutex); usleep(1000 * 500); } pthread_exit(&buy);}void *sellCallBack(void *data) { while (tag) { //线程锁 pthread_mutex_lock(&mutex); queue.push(1); LOGD("生产者生产了一个产品,并通知消费者可以消费了,目前产品总数为:%d", queue.size()); //发送信号激活等待的线程 pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); sleep(5); } pthread_exit(&sell);}//生产者消费者线程extern "C"JNIEXPORT void JNICALLJava_com_example_jnithread_ThreadDemo_startBuyThread(JNIEnv *env, jobject thiz) { for (int i = 0; i < 10; i++) { queue.push(i); } //初始化线程锁 pthread_mutex_init(&mutex, NULL); //初始化线程通知 pthread_cond_init(&cond, NULL); pthread_create(&buy, NULL, buyCallBack, NULL); pthread_create(&sell, NULL, sellCallBack, NULL);}#include "JavaListener.h"JavaVM *jvm;JavaListener *javaListener;pthread_t childThread;void *childCallBack(void *data) { JavaListener *childjavaListener = (JavaListener *) data; sleep(5); childjavaListener->onError(1, 200, "godv c++ call java child thread"); pthread_exit(&childThread);}extern "C"JNIEXPORT void JNICALLJava_com_example_jnithread_ThreadDemo_cCallBackJava(JNIEnv *env, jobject thiz) { //此处jobj需要处理成全局的这样子线程主线程都能用 javaListener = new JavaListener(jvm, env, env->NewGlobalRef(thiz)); //主线程调用 javaListener->onError(0, 100, "godv c++ call java main thread"); //第二个NULL用作childCallBack的data pthread_create(&childThread, NULL, childCallBack, javaListener);}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *unused) { JNIEnv *env; jvm = vm; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return -1; } return JNI_VERSION_1_6;}
c++ call java 的类
GCallJava.h
#ifndef RTMPSUC_GCALLJAVA_H#define RTMPSUC_GCALLJAVA_H#include "jni.h"#define G_THREAD_MAIN 1#define G_THREAD_CHILD 2class GCallJava {public: JNIEnv *jniEnv = NULL; JavaVM *javaVm = NULL; jobject jobj; jmethodID jmid_connecting;public: GCallJava(JavaVM *javaVm, JNIEnv *jniEnv, jobject *jobj); ~GCallJava(); void onConnecting(int type);};#endif //RTMPSUC_GCALLJAVA_H
GCallJava.cpp
#include "GCallJava.h"GCallJava::GCallJava(JavaVM *javaVm, JNIEnv *jniEnv, jobject *jobj) { this->javaVm = javaVm; this->jniEnv = jniEnv; this->jobj = jniEnv->NewGlobalRef(*jobj); jclass jlz = jniEnv->GetObjectClass(this->jobj); jmid_connecting = jniEnv->GetMethodID(jlz, "onConnecting", "()V");}GCallJava::~GCallJava() { jniEnv->DeleteGlobalRef(jobj); javaVm = NULL; jniEnv = NULL;}void GCallJava::onConnecting(int type) { if (type == G_THREAD_CHILD) { JNIEnv *jniEnv; if (javaVm->AttachCurrentThread(&jniEnv, 0) != JNI_OK) { return; } jniEnv->CallVoidMethod(jobj, jmid_connecting); javaVm->DetachCurrentThread(); } else { jniEnv->CallVoidMethod(jobj, jmid_connecting); }}
native-lib.cpp
#include#include #include "RtmpPush.h"/********************************************************回调***************************************/#include "GCallJava.h"GCallJava *gCallJava = NULL;JavaVM *javaVm = NULL;/********************************************************回调***************************************/RtmpPush *rtmpPush = NULL;extern "C"JNIEXPORT void JNICALLJava_com_example_glivepush_push_PushVideo_initPush(JNIEnv *env, jobject thiz, jstring pushUrl_) { // TODO: implement initPush() const char *pushUrl = env->GetStringUTFChars(pushUrl_, 0); /********************************************************回调***********************************/ gCallJava = new GCallJava(javaVm, env, &thiz); rtmpPush = new RtmpPush(pushUrl, gCallJava); /********************************************************回调***********************************/ rtmpPush->init(); env->ReleaseStringUTFChars(pushUrl_, pushUrl);}/********************************************************回调***************************************/extern "C"JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env; javaVm = vm; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return -1; } return JNI_VERSION_1_6;}extern "C"JNIEXPORT void JNICALLJNI_OnUnload(JavaVM *vm, void *reserved) { javaVm = NULL;}/********************************************************回调***************************************/
androidlog
//// Created by guosy on 20-10-15.//#ifndef GODVMUSIC_GODVLOG_H#define GODVMUSIC_GODVLOG_H#endif //GODVMUSIC_GODVLOG_H#include "android/log.h"#define LOG_TAG "godv"#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)add_library( native-lib SHARED ${CMAKE_SOURCE_DIR}/src/main/cpp/native-lib.cpp ${CMAKE_SOURCE_DIR}/src/main/cpp/JavaListener.cpp )target_link_libraries( native-lib log )
转载地址:http://ebzo.baihongyu.com/