Android - NDK :JNI实现异步回调

news2025/1/12 4:08:24

在android代码中,通过JNI调用c层子线程执行耗时任务,在c层子线程中把结果回调到android层,
C语言小白,请批评指正!
使用场景

android层代码:


import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.hisign.callback.MyCallback;
import com.hisign.callback.MyCallbackManager;
import com.hisign.device.databinding.ActivityMainDeviceBinding;

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("broadcast");
    }

    private ActivityMainDeviceBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainDeviceBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        binding.btnAsync.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MyCallbackManager.getInstance().doAsyncWork(new MyCallback() {
                    @Override
                    public void onStart() {
                        runOnUiThread(() -> Toast.makeText(MainActivity.this, "onStart...", Toast.LENGTH_SHORT).show());
                    }

                    @Override
                    public void onResult(String result) {
                        runOnUiThread(() -> binding.tvDev.setText(result));
                    }

                    @Override
                    public void onEnd() {
                        runOnUiThread(() -> {
                            Toast.makeText(MainActivity.this, "onEnd !!!", Toast.LENGTH_SHORT).show();
                            Log.d("lixm", "run: onEnd...");
                        });
                    }
                });
            }
        });
    }
}

activity_main_device.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:id="@+id/sample_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnAsync"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="异步回调"
        tools:ignore="MissingConstraints" />

    <TextView
        android:id="@+id/tvDev"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center_horizontal"
        android:textSize="40sp"
        android:textStyle="bold"/>
</LinearLayout>

MyCallback.java

public interface MyCallback {
    public void onStart();
    public void onResult(String result);
    public void onEnd();
}

MyCallbackManager.java


public class MyCallbackManager {
    private static MyCallbackManager instance;
    private MyCallbackManager(){
    }

    public static MyCallbackManager getInstance(){
        if(instance == null){
            synchronized (MyCallbackManager.class){
                if(instance == null){
                    instance = new MyCallbackManager();
                }
            }
        }
        return instance;
    }

    public native void doAsyncWork(MyCallback callback);
}


jni代码

thread_callback.cpp

#include "callback/ThreadCallback.h"
#include "iostream"
#include <jni.h>
#include "jniLog.h"
using namespace std;

// 在线程里面调用的,都需要声明为全局变量
JavaVM *jvm;
jobject mCallBackObj;

jmethodID resultMid;
jmethodID endMid;
JNIEnv *mEnv;
int mIsDetach = JNI_FALSE;

extern "C"
JNIEXPORT void JNICALL
Java_com_hisign_callback_MyCallbackManager_doAsyncWork(JNIEnv *env, jobject thiz,
        jobject callback) {
    LOGI("native _doAsyncWork...");

    //JavaVM是虚拟机在JNI中的表示,等下再其他线程回调java层需要用到
    env->GetJavaVM(&jvm);
    // 三步曲
    // 1 获取java层的类对象
    mCallBackObj = env->NewGlobalRef(callback);  // 创建一个jni全局引用
    jclass clz = env->GetObjectClass(callback);
    // 2 获取java层的函数
    jmethodID startMid = env->GetMethodID(clz,"onStart", "()V");
    // 这两个方法因为要在子线程中回调,所以声明为全局的
    resultMid = env->GetMethodID(clz,"onResult", "(Ljava/lang/String;)V");
    endMid = env->GetMethodID(clz,"onEnd", "()V");
    // 3 调用函数
    env->CallVoidMethod(mCallBackObj,startMid);

    MyCallback myCallback = [](std::string ret){  // 子线程中计算结果的回调
        //获取当前native线程是否有没有被附加到jvm环境中
        int envStatus = jvm->GetEnv((void **) &mEnv, JNI_VERSION_1_6);
        if(envStatus == JNI_EDETACHED){
            //如果没有, 主动附加到jvm环境中,获取到mEnv
            if (jvm->AttachCurrentThread(&mEnv, NULL) != 0) {
                return;
            }
            mIsDetach = JNI_TRUE;
        }
        // 回调数据到java层
        jstring jstr = mEnv->NewStringUTF(ret.c_str());         // 生成java层的String(jstring)
        mEnv->CallVoidMethod(mCallBackObj, resultMid, jstr);    // 回调到java层
    };
    CallbackEnd cbend = [](){   // 任务完成的回调
        if(mIsDetach){
            mEnv->CallVoidMethod(mCallBackObj,endMid);
            //释放当前线程
            jvm->DetachCurrentThread();
            mEnv = NULL;
        }
    };
    doAsyncWork(myCallback,cbend);
}


ThreadCallback.h

//
// Created by lixm on 2025/1/6.
//
#ifndef BROADCASTNATIVE_THREADCALLBACK_H
#define BROADCASTNATIVE_THREADCALLBACK_H

#include <functional>
typedef std::function<void(std::string)> MyCallback;
typedef std::function<void()> CallbackEnd;
void doAsyncWork(MyCallback MyCallback,CallbackEnd callbackEnd);
#endif //BROADCASTNATIVE_THREADCALLBACK_H

ThreadCallback.cpp

#include <thread>
#include "ThreadCallback.h"
#include "iostream"
#include "../jniLog.h"
#include "unistd.h"
using namespace std;


/**
 * 执行耗时操作
 * @param callback  异步回调
 */
void AsyncWork(MyCallback mycb,CallbackEnd callbackEnd){
    int i = 10;
    while(i -- > 0){
        sleep(1);  // 休眠1秒,模拟耗时操作(unistd.h)
        mycb(to_string(i));
    }
    callbackEnd();
}

void doAsyncWork(MyCallback myCallback,CallbackEnd callbackEnd){
    /**
     * 这里有三个参数
     * 第一个参数是子线程执行的函数
     * 第二个参数是函数的参数(回调计算结果)
     * 第三个参数是函数的参数(回调计算完成)
     */
    thread t1(AsyncWork,myCallback,callbackEnd);
    //t1.join();  // 主线程阻塞,等待线程执行完成
    t1.detach();
}

CmakeLists.txt

cmake_minimum_required(VERSION 3.18.1)

project("broadcast")
add_library( # Sets the name of the library.
        broadcast
        SHARED
        thread_callback.cpp
        callback/ThreadCallback.cpp)

find_library(log-lib log)
target_link_libraries(broadcast ${log-lib})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2275289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Altium】AD使用智能粘贴功能把多个网络标签改成端口

1、 文档目标 使用智能粘贴功能把多个网络标签&#xff08;net lable&#xff09;改成端口&#xff08;port&#xff09; 2、 问题场景 客户有一份原理图&#xff0c;网络用的是net label&#xff0c;没用Port&#xff0c;然后创建一个sheet symbol&#xff0c;但是sheet sy…

软件系统安全逆向分析-混淆对抗

1. 概述 在一般的软件中&#xff0c;我们逆向分析时候通常都不能直接看到软件的明文源代码&#xff0c;或多或少存在着混淆对抗的操作。下面&#xff0c;我会实践操作一个例子从无从下手到攻破目标。 花指令对抗虚函数表RC4 2. 实战-donntyousee 题目载体为具有漏洞的小型软…

01 springboot集成mybatis后密码正确但数据库连接失败

01 springboot集成mybatis后密码正确但数据库连接失败 问题描述&#xff1a; 1.datasource配置&#xff1a; //application.yaml spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mp?useUnicodetrue&characterEncodingUTF-8&autoReconnecttrue&serverTime…

Python基于jieba和wordcloud绘制词云图

【Cesium】自定义材质&#xff0c;添加带有方向的滚动路线 &#x1f356; 前言&#x1f3b6;一、实现过程✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 Python基于jieba和wordcloud绘制词云图 &#x1f3b6;一、实现过程 读取文本…

保证Mysql数据库到ES的数据一致性的解决方案

文章目录 1.业务场景介绍1.1 需求分析1.2 技术实现方案 2.业界常用数据一致性方案分析2.1 同步双写方案2.2 MQ异步双写方案2.3 扫表定期同步方案2.4 监听binlog同步方案 1.业务场景介绍 1.1 需求分析 某知名的在线旅游平台&#xff0c;在即将到来的春季促销活动之前&#xff…

文件搜索工具Everything

软件介绍 Everything 是一款运行于 Windows 系统的轻量级、高效的文件搜索工具 软件功能 1、基本搜索 在搜索框输入关键词&#xff0c;即可快速找到包含该关键词的文件和文件夹。 2、高级搜索 支持多种高级搜索语法&#xff0c;如.exe&#xff1a;可只返回特定扩展名的结果…

【面试题】技术场景 6、Java 生产环境 bug 排查

生产环境 bug 排查思路 分析日志&#xff1a;首先通过分析日志查看是否存在错误信息&#xff0c;利用之前讲过的 elk 及查看日志的命令缩小查找错误范围&#xff0c;方便定位问题。远程 debug 适用环境&#xff1a;一般公司正式生产环境不允许远程 debug&#xff0c;多在测试环…

【UE5 C++课程系列笔记】25——多线程基础——FGraphEventRef的简单使用

目录 概念 使用示例1 使用示例2 概念 FGraphEventRef 本质上是对一个异步任务或者一组相关异步任务在虚幻引擎任务图系统中的一种引用&#xff08;reference&#xff09;。虚幻引擎的任务图系统用于高效地调度和管理各种异步任务&#xff0c;协调它们的执行顺序以及处理任务…

DeepSeek:性能强劲的开源模型

deepseek 全新系列模型 DeepSeek-V3 首个版本上线并同步开源。登录官网 chat.deepseek.com 即可与最新版 V3 模型对话。 性能对齐海外领军闭源模型​ DeepSeek-V3 为自研 MoE 模型&#xff0c;671B 参数&#xff0c;激活 37B&#xff0c;在 14.8T token 上进行了预训练。 论…

使用 SQL 和表格数据进行问答和 RAG(1)—数据库准备

一. 从 .sql/csv/xlsx 文件创建 sqlite 数据库。 要从.sql文件准备 SQL DB&#xff0c;这里会将创建数据库的代码放到了&#xff0c;将文件复制到data/sql目录中&#xff0c;然后在终端中的项目文件夹中执行&#xff1a; pip install sqlite3现在创建一个名为sqldb的数据库&a…

用否定法去跳脱圈层

在这个充满竞争和诱惑的时代&#xff0c;许多人发现自己被困在了一个看似舒适却实则束缚重重的圈层之中。这个圈层&#xff0c;可能是由底层人的思维惯性、不良习惯、无谓消费、攀比心理等构成的。要真正实现自我提升&#xff0c;跳出这个圈层&#xff0c;就需要我们运用否定法…

C++类的引入

C中类的前身 1> 面向对象三大特征&#xff1a;封装、继承、多态 2> 封装&#xff1a;将能够实现某一事物的所有万事万物都封装到一起&#xff0c;包括成员属性&#xff08;成员变量&#xff09;&#xff0c;行为&#xff08;功能函数&#xff09;都封装在一起&#xff…

Postman配置环境变量

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Postman是一套比较方便的接口测试工具&#xff0c;但我们在使用过程中&#xff0c;可能会出现创建了API请求&#xff0c;但API的URL会随着服务器IP地址的变化而改…

新能源网站提升用户体验的关键

新能源网站的用户体验对于吸引和留住访问者至关重要。一个优秀的用户体验可以增加用户的满意度&#xff0c;提高他们对网站的忠诚度。在设计新能源网站时&#xff0c;关键在于简洁明了的界面和易于导航的布局。用户应该能够轻松找到他们需要的信息&#xff0c;而不会感到困惑或…

【Unity3D日常开发】Unity3D中适用WEBGL打开Window文件对话框打开/上传文件

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 Unity3D发布的WEBGL程序是不支持直接的I/O操…

ElasticSearch内存占用率过高怎么办?

文章目录 1&#xff0c;先用top看看各个进程的内存占用情况2&#xff0c;不能简单的杀死进程&#xff0c;然后再重启。3&#xff0c;查看一下ElasticSearch进程的具体启动情况4&#xff0c;修改Elasticsearch 的Java堆内存 1&#xff0c;先用top看看各个进程的内存占用情况 先…

DC/AC并网逆变器模型与仿真MATLAB

DC/AC并网逆变器是一种将直流电&#xff08;DC&#xff09;转化为交流电&#xff08;AC&#xff09;&#xff0c;并将其与电网并联的设备。它的核心功能是实现直流电源&#xff08;如光伏电池板或储能电池&#xff09;与电网的有效连接&#xff0c;同时保证输出电能质量满足电网…

Flink三种集群部署模型

这里写自定义目录标题 Flink 集群剖析Flink 应用程序执行Flink Session 集群&#xff08;Session Mode&#xff09;Flink Job 集群&#xff08;以前称为per-job&#xff09;Flink Application 集群&#xff08;Application Mode&#xff09; 参考 Flink 集群剖析 Flink 运行时…

JVM实战—12.OOM的定位和解决

大纲 1.如何对系统的OOM异常进行监控和报警 2.如何在JVM内存溢出时自动dump内存快照 3.Metaspace区域内存溢出时应如何解决(OutOfMemoryError: Metaspace) 4.JVM栈内存溢出时应如何解决(StackOverflowError) 5.JVM堆内存溢出时应该如何解决(OutOfMemoryError: Java heap s…

一文读懂「LoRA」:大型语言模型的低秩适应

LoRA: Low-Rank Adaptation of Large Language Models 前言 LoRA作为大模型的微调框架十分实用&#xff0c;在LoRA出现以前本人都是通过手动修改参数、优化器或者层数来“炼丹”的&#xff0c;具有极大的盲目性&#xff0c;但是LoRA技术能够快速微调参数&#xff0c;如果LoRA…