美文网首页
JNI 中的线程

JNI 中的线程

作者: __Y_Q | 来源:发表于2023-01-28 15:09 被阅读0次

相关结论

  • JNIEnv 无法跨线程, 可以跨函数.
  • jobject 无法跨线程, 无法跨函数.
  • JavaVM 可以跨线程,跨行数.

在实际开发中, 很有可能在 JNI 中做一些耗时操作, 就需要在 JNI 中用到子线程. 下面用一个栗子🌰来学习.

Java 代码

public class MainActivity extends AppCompatActivity {

    // Used to load the 'myapplication' library on application startup.
    static {
        System.loadLibrary("myapplication");
    }

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        //JNI 调用
        nativeThreadInvokeJava();
    }

    //在 JNI 中耗时操作完毕后,调用 java 层的此方法
    public void updateUI(){
        if(Looper.myLooper() == Looper.getMainLooper()) {
            Toast.makeText(this, "主线程更新UI", Toast.LENGTH_SHORT).show();
        }else{
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, "已切换到主线程更新UI", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    //定义 JNI 方法.
    native void nativeThreadInvokeJava();
}

JNI 代码

#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h> //导入线程需要的包

JavaVM *_vm;

#define _MY_LOGE(...) __android_log_print(ANDROID_LOG_DEBUG, "JNI", __VA_ARGS__);

struct myContext{
    jobject instance;
   //JNIEnv *env; 无法在子线程使用 JNIEnv
};

int JNI_OnLoad(JavaVM *vm, void *re){
    _vm = vm;
    return  JNI_VERSION_1_6;
}

//在子线程要执行的方法
void * myThreadTask(void *arges){
    //将 native 线程附加到 java 虚拟机, 获得一个当前子线程专用的 jniEnv
    JNIEnv * env = nullptr;
    jint i = _vm->AttachCurrentThread(&env, nullptr);
    if(i != JNI_OK) {
        return 0;
    }
    //执行耗时操作.需要通知 java 状态更新
    myContext * context = static_cast<myContext *>(arges);
    jclass mainActivityObj = env->GetObjectClass(context->instance);
    jmethodID methodId = env->GetMethodID(mainActivityObj, "updateUI", "()V"); //获得方法ID
    env->CallVoidMethod(context->instance, methodId);
    delete(context);
    context = 0;
    env->DeleteGlobalRef(context->instance);//删除全局引用
    _vm->DetachCurrentThread(); //附加完, 之后完成后,需要分离
    return 0;
}

extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_myapplication_MainActivity_nativeThreadInvokeJava(JNIEnv *env, jobject instance) {
    myContext *context = new myContext;
    //context->env = env; //在子线程中, 无法使用这里传递过去的 JNIEnv; JNIEnv 不能跨线程.
    context->instance = env->NewGlobalRef(instance); //将上下文对象传入到结构体
    pthread_t  pid; //创建一个句柄
    pthread_create(&pid, 0, myThreadTask ,context); //启动线程
    pthread_join(pid, nullptr);
}

相关文章

  • 3-ndk学习之jni基础篇(3)

    jni多线程操作 这里的效果是在jni中开启子线程,然后在子线程直接调用Activity的方法jni中,jvm是跨...

  • 八、JNI-JNI补充功能

    JNI和线程 注册本地方法 #1. JNI和线程 1.1 规约 当编写JNI函数时,有如下规约是必须要遵守的: J...

  • JNI收集知识

    Android JNI 中的线程操作[https://link.zhihu.com/?target=https%3...

  • Executor线程池原理与源码解读

    线程实现方式 Thread、Runnable、Callable 注意:启动Thread线程只能用start(JNI...

  • JNI开发-线程操作

    JNI开发-线程操作 线程操作 JNIEnv指针仅在创建它的线程有效。C/C++创建的线程默认是没有附加到JVM的...

  • jni学习笔记

    主要涉及知识点 1.JNI_OnLoad2.动态注册和静态注册3.多线程4.在子线程中回调java方法 代码

  • JNI编程-动态注册及native线程调用Java

    本篇主要讲解JNI的一些高级写法和线程,文章内容都非常简单。 JNI_OnLoad 上一章讲的JNI 编程详解Ja...

  • JNI完全指南(八)——NIO

    标签(空格分隔): JNI完全指南 发布于:作业部落、简书、CSDN博客 上一篇:JNI完全指南(七)——多线程 ...

  • Android NDK - JNI

    JNI基础知识 数据类型 JNI系统类型:JNIEnv(线程上下文)基本数据类型:int/float/long等等...

  • NDK基础(五)—— 线程

    先创建两个需要在子线程中执行的函数 由于JNI中的线程不是Java平台的一部分,因此虚拟机不能识别他们,为了和Ja...

网友评论

      本文标题:JNI 中的线程

      本文链接:https://www.haomeiwen.com/subject/broyhdtx.html