jni多线程操作
这里的效果是在jni中开启子线程,然后在子线程直接调用Activity的方法
jni中,jvm是跨线程的,但是env不可以跨线程使用,所以在子线程中需要新创建一个env,创建env需要使用到jvm,所有需要重写JIN_Onload方法,这个方法是System.loadLibrary("native-lib")加载so库后调用的,可以拿到jvm对象。
直接撸码:
MainActivity中:
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testThread();
}
private native void testThread();
@Override
protected void onDestroy() {
super.onDestroy();
unThread();
}
public native void unThread();
// AndroidUI操作,让C++线程里面来调用
public void updateUI() {
if (Looper.getMainLooper() == Looper.myLooper()) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("UI")
.setMessage("updateUI run ...")
.setPositiveButton("知道了", null)
.show();
} else {
Log.d("MainActivity", "updateUI: 所属与子线程.......只能打印日志了");
runOnUiThread(new Runnable() {
@Override
public void run() {
new AlertDialog.Builder(MainActivity.this)
.setTitle("UI")
.setMessage("updateUI run ...")
.setPositiveButton("知道了", null)
.show();
}
});
}
}
native-lib中:
#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>
#include <android/log.h>
#define TAG "ftd"
#define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__)
JavaVM * jvm;
//此方法是MainActivity中 System.loadLibrary("native-lib");后调这的
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM * javaVm, void * pVoid) {
//jvm是跨平台的,env不能跨平台,所以需要重写这个方法获取到jvm对象,通过jvm对象获取的新的env使用
jvm = javaVm;
return JNI_VERSION_1_6;
}
//全部引用,这里的jobject1实际上就是MainActivity
jobject jobject1;
void * customThread(void * pVoid){
JNIEnv * env = nullptr; // 全新的env
int result = jvm->AttachCurrentThread(&env, 0); // 把native的线程,附加到JVM
if (result != 0) {
return 0;
}
jclass mainActivityClass = env->GetObjectClass(jobject1);
// 拿到MainActivity的updateUI
const char * sig = "()V";
jmethodID updateUI = env->GetMethodID(mainActivityClass, "updateUI", sig);
env->CallVoidMethod(jobject1, updateUI);
// 解除附加到JVM 的native线程,如果不解除是会崩溃的
jvm->DetachCurrentThread();
return 0;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testThread(JNIEnv *env, jobject instance) {
pthread_t pthreadId;
// 全局的,就不会被释放,所以可以在线程里面用
jobject1 = env->NewGlobalRef(instance);
pthread_create(&pthreadId,0,customThread,instance);
pthread_join(pthreadId,0);
}
/*
* 释放全局引用
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_unThread(JNIEnv *env, jobject instance) {
if(instance!=NULL){
env->DeleteGlobalRef(jobject1);
jobject1 = NULL;
}
}
动态注册
每次在activity中写好native方法,alt+回车自动生成的jni方法,类似于这样的(
Java_com_example_myapplication_MainActivity_registerJava01),这些都是静态注册,简单,命名规则就是全包名+类名+方法名,缺点就是不安全,同理,动态注册,优点就是安全,自己起名字,缺点就是很麻烦。
我认为它很绕,很不好理解,但是都是一些固定写法,写多了就熟了
MainActivity中:
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerJava01("李AAAAAAAAAAAAAA");
}
// 动态注册的函数
public native void registerJava01(String text);
native-lib中:
/**
* 随意取名字了,
* @param env
* @param instance
* @param text
*/
void register01(JNIEnv * env, jobject instance, jstring text) {
const char * textValue = env->GetStringUTFChars(text, NULL);
LOGD("动态注册的函数执行了 %s", textValue);
env->ReleaseStringUTFChars(text, textValue);
}
/**
* 通过查看源码可以得知是一个结构体
*/
static const JNINativeMethod jniNativeMethod[] = {
{"registerJava01", "(Ljava/lang/String;)V", (void *)(register01)}
};
//此方法是MainActivity中 System.loadLibrary("native-lib");后调这的
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM * javaVm, void * pVoid) {
// 通过虚拟机 创建全新的 evn
JNIEnv * jniEnv = nullptr;
jint result = javaVm->GetEnv(reinterpret_cast<void **>(&jniEnv), JNI_VERSION_1_6); // 参数2:是JNI的版本 NDK 1.6 JavaJni 1.8
if (result != JNI_OK) {
return -1; // 主动报错
}
const char * mainActivityClassStr = "com/example/myapplication/MainActivity";
jclass mainActivityClass = jniEnv->FindClass(mainActivityClassStr);
jniEnv->RegisterNatives(mainActivityClass, jniNativeMethod, sizeof(jniNativeMethod) / sizeof(JNINativeMethod)); // 参数三:到底要动态注册几个
return JNI_VERSION_1_6;
}
如果有不对的地方,希望大家在评论区多多指正,共同学习,谢谢大家。
网友评论