首先更新一些知识点
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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="普通线程"
android:onClick="run"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="生产者消费者线程"
android:onClick="buy"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="c++calljava主线程/子线程"
android:onClick="callJavaMain"/>
</LinearLayout>
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 <jni.h>
#include <string>
#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 JNICALL
Java_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<int> 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 JNICALL
Java_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 JNICALL
Java_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 2
class 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 <jni.h>
#include <string>
#include "RtmpPush.h"
/********************************************************回调***************************************/
#include "GCallJava.h"
GCallJava *gCallJava = NULL;
JavaVM *javaVm = NULL;
/********************************************************回调***************************************/
RtmpPush *rtmpPush = NULL;
extern "C"
JNIEXPORT void JNICALL
Java_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 JNICALL
JNI_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 JNICALL
JNI_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 )