JNI入门课程第七章-JNI中创建线程通知安卓刷新

PS:文章不小心写重了,参见另一篇,那篇写的更详细https://blog.csdn.net/rzleilei/article/details/122475387

练习题需求:

点击界面的一个按钮,调用JNI方法,JNI方法中启动JNI线程,JNI线程中不断回调通知安卓进行界面刷新。

初版代码:

安卓代码:

else if (v?.id == R.id.button6) {
            //动态注册
            var dynamicRegister = DynamicRegister()
//            viewHolder.resultText?.text = "$result,$result2"
            //新需求:C层启动一个线程,主动通知java层的刷新界面。
            dynamicRegister.refresh("ttA")
            Log.i("lxllest","tta")
        }
 fun showMessage(str: String) {
        viewHolder.resultText?.text = str
    }

JNI代码:

void nativeRefresh(JNIEnv *env, jclass clazz,jstring title){
    mEnv = env;
    Param param;
    param.a = title;
    param.b = "1";
    param.c = 1;
//    int param = 123;
    pthread_t pt;
    __android_log_print(ANDROID_LOG_INFO,"lxltestjni","nativeRefresh start,tmp.c:%d",param.c);
    pthread_create(&pt,NULL,freshAndroidPage,&param);
    sleep(1);//这里加上sleep1秒,就不会释放。但是过了1秒之后param还是会被释放
}

JNI线程

void * freshAndroidPage(void *arg){
    Param tmp = *(Param *)arg;
    int i=0;
    __android_log_print(ANDROID_LOG_INFO,"lxltestjni","freshAndroidPage start,tmp.c:%d",tmp.c);
    while (i++<10)
    {
        __android_log_print(ANDROID_LOG_INFO,"lxltestjni","i:%d", i);
//        jclass cls = env->GetObjectClass(activity);
//        jmethodID id = env->GetMethodID(cls, "showMessage", "(Ljava/lang/String;)V");
//        jstring message = env->NewStringUTF(reinterpret_cast<const char *>(title + ":"[i]));
//        env->CallVoidMethod(activity, id, message);
        sleep(5);
    }
}

排查流程:

问题1:

现象:线程中接收到的传入的参数都是空值。

原因:JNI方法被调用之后,方法内的局部变量会被释放,从而导致线程中指针获取到的值为空。

解决方案:把Param转为全局引用

这样的话,先保证Param中的值可以传入到线程当中了,但是我们的目标是把activity也传递过去。

问题2:传递activity引用到线程。

如果直接传入jobject是不行的,因为jobject也是属于局部引用。跨线程是不能正常使用的。

我们要使用NewGlobalRef进行包装,封装成全局变量才可以正常使用。

最终代码:

java代码不变,只改变JNI代码即可

Param param;
JavaVM *g_vm;

void *freshAndroidPage(void *arg) {
    JNIEnv *env;
    g_vm->AttachCurrentThread(&env, nullptr);
    Param tmp = param;
    jobject activity = tmp.activity;
    const char *title = env->GetStringUTFChars(tmp.title, JNI_FALSE);
    int i = 0;
    __android_log_print(ANDROID_LOG_INFO, "lxltestjni",
                        "freshAndroidPage start,tmp.charTitle:%s,title:%s", tmp.charTitle, title);
    while (i++ < 10) {
        __android_log_print(ANDROID_LOG_INFO, "lxltestjni", "i:%d,charTitle:%s", i, tmp.charTitle);
        jclass cls = env->GetObjectClass(activity);
        jmethodID id = env->GetMethodID(cls, "showMessage", "(Ljava/lang/String;)V");

        strchr(tmp.charTitle,i);
        std::string result = tmp.charTitle;
        result.append(std::to_string(i));
        jstring message = env->NewStringUTF(result.c_str());
        env->CallVoidMethod(activity, id, message);
        sleep(5);
    }
    g_vm->DetachCurrentThread();
}

void nativeRefresh(JNIEnv *env, jclass clazz, jstring title, jobject activity) {
    param.title = static_cast<jstring>(env->NewGlobalRef(title));
    param.charTitle = env->GetStringUTFChars(title, JNI_FALSE);
    param.activity = env->NewGlobalRef(activity);
    param.i = 1;
//    int param = 123;
    pthread_t pt;
    __android_log_print(ANDROID_LOG_INFO, "lxltestjni", "nativeRefresh start,tmp.c:%d", param.i);
    pthread_create(&pt, NULL, freshAndroidPage, &param);//这里的param无用
//    sleep(1);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失落夏天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值