androidJNI调用c++字符串

6 篇文章 0 订阅
6 篇文章 0 订阅

 在Android中用C/C++开发一部分功能时,有时候要把参数传到java层,java层来做相应的处理和更新UI。

所以安卓有一个JNI来给开发者们调用这些数据和处理。但是这样会损失一些性能,第一,java跨平台的优势没有了,第二,当

c/c++写的代码出问题时候,程序会崩溃,不容易找错,所以建议调用时候要多加LOGI打印,在关键调用地方记得要添加返回

值,这样能够省掉很多时间来找错误。


 这样才能把信息传递给java层。当C/C++文件很多时,里面线程也很多时, 这时就需要我们使用统一的回调函数来处理了,不然

会很混乱的
 
 实现思路:

        1、jni里面调用java方法的大致步骤是:根据jobject获取jclass(静态方法就不用这一步了)--> 获取jmethodid --> 调用方法。

        2、jni里面调用java方法的环境分为2种。

        第一种:在env所在线程调用java方法,这种情况不需要做特殊处理,直接按照步骤执行即可。

        第二种:在pthread子线程调用java方法,这种情况下就需要做处理了。在jni中,子线程中是不能直接调用JNIEnv对象的,也不能直接调用env线程中的jobject对象,

            因为:jni中,JNIEnv是和线程相关的,每一个native方法所在线程就有一个当前线程相关的JNIEnv对象,而pthread线程中是不能调用native方法所在线程的JENnv对象的,

            解决办法是:利用JavaVM虚拟机,JavaVM是和进程相关的,一个进程里面的JavaVM都是同一个,所以在pthread线程中就可以通过JavaVM来获取(AttachCurrentThread)

            当前线程的JNIEnv指针,然后就可以使用JNIEnv指针操作数据了;还有在pthread线程中调用jobject对象时,首先需要把native线程里面的jobject创建全局引用(env->NewGlobalRef(jobj)),

            其返还的jobject对象就可以在程序中使用了。

        3、在JNI_OnLoad中获取我们需要的JavaVM指针。

创建.h文件


    void  WlListener(JavaVM* vm, _JNIEnv *jenv, jobject obj);


    void onError(int type, int code, const char *msg);

	JavaVM* jvm;//java虚拟机
    _JNIEnv *jenv;//native线程env对象
    jobject jobj;//全局对象
    jmethodID jmid;//java 方法id,可以根据实际情况创建多个。

创建.cpp文件

void WlListener(JavaVM* vm, _JNIEnv *env, jobject obj)
	{
    jvm = vm;
    jenv = env;
    jobj = obj;
    jclass classvideo = env->GetObjectClass(jobj);
    if(!classvideo)
    {
      //  LOGD("get class error...");
    }
    jmid = env->GetMethodID(classvideo,"onError","(ILjava/lang/String;)V");
    if(!jmid)
    {
       // LOGD("get jmethodIO error...:);
        return;
    }
}

void onError(int type, int code, const char *msg) {
    if(type == 0)
    {
        jstring jmsg = jenv->NewStringUTF(msg);
        jenv->CallVoidMethod(jobj, jmid, code, jmsg);
        jenv->DeleteLocalRef(jmsg);
    }
    else if(type == 1)
    {
        JNIEnv *env;
        jvm->AttachCurrentThread(&env, 0);

        jstring jmsg = env->NewStringUTF(msg);
        env->CallVoidMethod(jobj, jmid, code, jmsg);
        env->DeleteLocalRef(jmsg);

        jvm->DetachCurrentThread();
    }
	

    
    其中:jvm参数是为了获取子线程中的JNIEnv;jenv参数是native线程中的,在native线程中使用;
    
    jobj是全局对象;jmid是要调用的java层的方法id,还可以有其他方法。
    
    2.然后创建jni层native-lib.cpp文件通过JNI_OnLoad获取JavaVM:

 

extern "C"
JNIEXPORT void JNICALL
Java_com_example_dell_sample_testJNI_UDPVideoRecvThreadID(
        JNIEnv* env,
        jobject  jobj) {

        WlListener(jvm, env, env->NewGlobalRef(jobj));//转化成全局变量.

        LOGI("JNIENV thread running START1...");
        //onError(0, 100, "JNIENV thread running success!");

        LOGI("create child thread START1...");
        pthread_create(&UDPVideoRecvThreadID, NULL, UdpVideoRecvTask,(void *)&UDP_VideoSocket);
}

    3.java方法实现
    //3、回调线程

    public native void callbackThread();
 
    private OnErrorListener onErrorListener;
 
    public void setOnErrorListener(OnErrorListener onErrorListener) {
        this.onErrorListener = onErrorListener;
    }
 
    //Jni调用此方法,把结果返回到java层
    public void onError(int code, String msg)
    {
        if(onErrorListener != null)
        {
            onErrorListener.onError(code, msg);
        }
    }
 
    public interface OnErrorListener
    {
        void onError(int code, String msg);
    }


    4.java中activity实现

   m_test.setOnErrorListener(new testJNI.OnErrorListener() {
            @Override
            public void onError(int code, String msg) {
                Log.d("lsx test", "code: " + code + ", msg: " + msg);
                Message message = Message.obtain();
                message.what = code;
                message.obj = msg;
                handler.sendMessage(message);
            }
        });

        //tv.setText(m_test.stringFromJNI());
       // m_test.init(str);
        //m_test.init(str);
       // m_test1.main();
    }

    class MyServiceConn implements ServiceConnection {
        // 服务被绑定成功之后执行
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // IBinder service为onBind方法返回的Service实例
            binder = (MyService.MyBinder) service;
            binder.getService().setDataCallback(new MyService.DataCallback() {
                //执行回调函数
                @Override
                public void dataChanged(String str) {
                    Message msg = new Message();
                    Bundle bundle = new Bundle();
                    bundle.putString("str", str);
                    //Log.d("Mac",str);
                    msg.setData(bundle);
                    //发送通知
                    handler.sendMessage(msg);
                    //m_test.init(str);
                    //m_test.init();
                }
            });
        }



    public void jniCallback(View view) {
        // ppNet.callbackThread();
        m_test.UDPVideoRecvThreadID();
    }

    Handler handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Toast.makeText(MainActivity.this, (String)msg.obj, Toast.LENGTH_SHORT).show();
        }
    };

这是一个c++写的接收mjpeg视频流然后用androidJNI调用的小插曲,文章有借鉴别人的d地方,时间赶,写的也比较随便,还有

android读取设备信息利用jni给到c++中,还有mjpeg解码等等内容等项目做完了再一段一段的更新分享。希望能够帮助到需要的

人,有希望交流的欢迎留言!

借鉴作者地址https://blog.csdn.net/ywl5320/article/details/78739211#comment

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值