jni不通过线程c回调java的函数
Posted luzhouxiaoshuai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jni不通过线程c回调java的函数相关的知识,希望对你有一定的参考价值。
整个工程的项目如下:
1、项目的思路是在activity中启动MyService这个服务,在服务中调用
JniScsManger类中的本地方法startNativeScsService,在
startNativeScsService的c代码实现中回调JniScsManger中的scsConnectStatus方法。
下面我们来看下两种代码的实现:
package com.cetcs.ecmapplication.jni.scs; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { super.onCreate(); JniScsManger.getInstances().startNativeScsService(); } }
activity的代码:
package im.weiyuan.com.jni2; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; import com.cetcs.ecmapplication.jni.scs.JniScsManger; import com.cetcs.ecmapplication.jni.scs.MyService; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(MainActivity.this, MyService.class); startService(intent); } }
package com.cetcs.ecmapplication.jni.scs; import android.util.Log; /** * Created by wei.yuan on 2017/6/7. */ public class JniScsManger { static { System.loadLibrary("jniscs"); } private static JniScsManger jniScsManger = null; private JniScsManger(){ } public static JniScsManger getInstances(){ if(jniScsManger == null){ jniScsManger = new JniScsManger(); } return jniScsManger; } public native int startNativeScsService(); public void scsConnectStatus(int status,String reason){ Log.d("123456",""+status+","+reason); } public void getScsStatus(){ Log.d("123456",""+","); } public int onProgressCallBack(long total, long already) { //自行执行回调后的操作 Log.d("123456",""+"onProgressCallBack"); System.out.println("total123456:"+total); System.out.println("already:"+already); return 1; } }
我们来看看本地native层实现的代码:
第一种方式:
// // Created by wei.yuan on 2017/6/7. // #include <android/log.h> #include <string.h> #include <stdio.h> #include <pthread.h> #include <time.h> #include <dlfcn.h> #include <jni.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> #include <assert.h> #include <android\\log.h> #include <errno.h> #include <pthread.h> #include "com_cetcs_ecmapplication_jni_scs_JniScsManger.h" //动态链接库路径 #define LIB_SCS_PATH "libServerCenter.so" #define LOG_TAG "SCS123456" #define LOGI_JniSCS(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) JNIEXPORT jint JNICALL Java_com_cetcs_ecmapplication_jni_scs_JniScsManger_startNativeScsService(JNIEnv * env, jobject jobj){ LOGI_JniSCS("start native ServerCenterService"); //jobj对象就是java层调用startNativeScsService的对象,那个类调用startNativeScsService对应的jobj就是那个对象 jclass javaClass = (*env)->FindClass(env, "com/cetcs/ecmapplication/jni/scs/JniScsManger"); if (javaClass == 0) { LOGI_JniSCS("Unable to find class"); return; } //获取要回调的方法ID jmethodID javaCallbackId = (*env)->GetMethodID(env, javaClass,"scsConnectStatus", "(ILjava/lang/String;)V"); if (javaCallbackId == NULL) { LOGI_JniSCS("Unable to find method:onProgressCallBack"); return; } //执行回调,注意第二个参数是jobj,不是javaClass (*env)->CallVoidMethod(env, jobj, javaCallbackId,1,(*env)->NewStringUTF(env, "Hello from JNI000.0.0.!")); return 4000000; }
第二种方式:
// // Created by wei.yuan on 2017/6/7. // #include <android/log.h> #include <string.h> #include <stdio.h> #include <pthread.h> #include <time.h> #include <dlfcn.h> #include <jni.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> #include <assert.h> #include <android\\log.h> #include <errno.h> #include <pthread.h> #include "com_cetcs_ecmapplication_jni_scs_JniScsManger.h" //动态链接库路径 #define LIB_SCS_PATH "libServerCenter.so" #define LOG_TAG "SCS123456" #define LOGI_JniSCS(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) JNIEXPORT jint JNICALL Java_com_cetcs_ecmapplication_jni_scs_JniScsManger_startNativeScsService(JNIEnv * env, jobject jobj){ LOGI_JniSCS("start native ServerCenterService"); //jobj对象就是java层调用startNativeScsService的对象,那个类调用startNativeScsService对应的jobj就是那个对象 jclass javaClass = (*env)->GetObjectClass(env, jobj); if (javaClass == 0) { LOGI_JniSCS("Unable to find class"); return; } //获取要回调的方法ID jmethodID javaCallbackId = (*env)->GetMethodID(env, javaClass,"scsConnectStatus", "(ILjava/lang/String;)V"); if (javaCallbackId == NULL) { LOGI_JniSCS("Unable to find method:onProgressCallBack"); return; } //执行回调,注意第二个参数是jobj,不是javaClass (*env)->CallVoidMethod(env, jobj, javaCallbackId,1,(*env)->NewStringUTF(env, "Hello from JNI000.0.0.!")); return 4000000; }
注意点:
FindClass是通过传java中完整的类名来查找java的class, 而GetObjectClass是通过传入jni中的一个java的引用来获取该引用的类型。 前者要求你必须知道完整的类名,后者要求在Jni有一个类的引用。
上面中传入的
(JNIEnv * env, jobject jobj)中的jobj就是调用startNativeScsService的对象,就是JniScsManger的一个对象实例。
FindClass是通过类名获得该对象的实例,
GetObjectClass是获得该对象的一个引用。
现在增加一个需求:
我们在上传新增加一个类:
我们要在startNativeScsService的c代码实现中回调Sb中的scsConnectStatus方法如何实现了,我们来看c层的代码
package com.cetcs.ecmapplication.jni.scs; import android.util.Log; /** * Created by wei.yuan on 2017/6/26. */ public class Sb { public void scsConnectStatus(int status,String reason){ Log.d("123456",""+status+","+reason); } }
// // Created by wei.yuan on 2017/6/7. // #include <android/log.h> #include <string.h> #include <stdio.h> #include <pthread.h> #include <time.h> #include <dlfcn.h> #include <jni.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> #include <assert.h> #include <android\\log.h> #include <errno.h> #include <pthread.h> #include "com_cetcs_ecmapplication_jni_scs_JniScsManger.h" //动态链接库路径 #define LIB_SCS_PATH "libServerCenter.so" #define LOG_TAG "SCS123456" #define LOGI_JniSCS(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) JNIEXPORT jint JNICALL Java_com_cetcs_ecmapplication_jni_scs_JniScsManger_startNativeScsService(JNIEnv * env, jobject jobj){ LOGI_JniSCS("start native ServerCenterService"); //jobj对象就是java层调用startNativeScsService的对象,那个调用startNativeScsService对应的jobj就是那个对象 jclass javaClass = (*env)->FindClass(env, "com/cetcs/ecmapplication/jni/scs/Sb"); if (javaClass == 0) { LOGI_JniSCS("Unable to find class"); return; } //构造Sb这个对象 jmethodID constructor = (*env)->GetMethodID(env, javaClass, "<init>", "()V"); //获取要回调的方法ID jmethodID javaCallbackId = (*env)->GetMethodID(env, javaClass,"scsConnectStatus", "(ILjava/lang/String;)V"); if (javaCallbackId == NULL) { LOGI_JniSCS("Unable to find method:onProgressCallBack"); return; } jobject obj = (*env)->NewObject(env, javaClass, constructor); //执行回调,注意第二个参数是obj,不是jobj (*env)->CallVoidMethod(env, obj, javaCallbackId,1,(*env)->NewStringUTF(env, "Hello from JNI000.0.0.!0..22")); return 4000000; }
程序代码的下载地址是:
https://pan.baidu.com/s/1gfosrp5
以上是关于jni不通过线程c回调java的函数的主要内容,如果未能解决你的问题,请参考以下文章
在java层用线程调用native方法 jni能回调主线程的方法吗?