android jni c++回调java{主线程/子线程} c++线程创建

26 篇文章 2 订阅
9 篇文章 2 订阅

首先更新一些知识点

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 )

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值