本文参考了http://www.cnblogs.com/lknlfy/archive/2012/03/16/2400786.html这篇博文,加了点自己的东西
废话不多说,贴代码上来
java的代码:
package com.example.jni_thread_demo; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; public class JNI_ThreadActivity extends Activity { private Button mButton = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_jni__thread); mButton = (Button)findViewById(R.id.button); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 调用JNI中的函数来启动JNI中的线程 mainThread(); } }); // 初始化JNI环境 setJNIEnv(); } //由JNI中的线程回调类方法 private static void fromJNI(int i) { Log.v("Java---------->", ""+i); } //自己定义的线程回调成员方法 private void From_JNI_Again (int i) { Log.v("Java_object------------>", ""+i); } // 本地方法 private native void mainThread(); private native void setJNIEnv(); static { System.loadLibrary("JNIThread"); } }
jni中的代码:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<pthread.h> #include<string.h> #include<assert.h> #include<jni.h> #include<android/log.h> #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "jni_thread", __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "jni_thread", __VA_ARGS__)) #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "jni_thread", __VA_ARGS__)) // 线程数 #define NUMTHREADS 5 // 指定要注册的类 #define JNIREG_CLASS "com/example/jni_thread_demo/JNI_ThreadActivity" // 全局变量 JavaVM* g_jvm = NULL; jobject g_obj = NULL; void* thread_fun(void* arg) { JNIEnv *env; jclass cls; jmethodID mid, mid1; // Attach主线程 if((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK) { LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); return NULL; } // 找到对应的类 cls = (*env)->GetObjectClass(env, g_obj); if(cls == NULL) { LOGE("FindClass() Error ......"); goto error; } // 再获得类中的方法 mid = (*env)->GetStaticMethodID(env, cls, "fromJNI", "(I)V"); if(mid == NULL) { LOGE("GetStaticMethodID() Error ......"); goto error; } // 最后调用java中的静态方法 (*env)->CallStaticVoidMethod(env, cls, mid, (int)arg); //获得类中的“成员”方法 mid1 = (*env)->GetMethodID(env, cls, "From_JNI_Again", "(I)V"); if(mid == NULL) { LOGE("GetMethodID() Error ......"); goto error; } // 最后调用类中“成员”方法 (*env)->CallVoidMethod(env, g_obj, mid1, (int)arg); //错误处理代码 error: //Detach主线程 if((*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK) { LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); } pthread_exit(0); } /* * Class: com_example_jni_thread_demo_JNI_ThreadActivity * Method: mainThread * Signature: ()V */ /*不用JNI_OnLoad时的复杂命名方式 JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_mainThread (JNIEnv *env, jobject obj) { int i; pthread_t pt[NUMTHREADS]; for(i=0; i<NUMTHREADS; i++) { // 创建线程,并指明调用的函数 pthread_create(&pt[i], NULL, &thread_fun, (void*)i); } }*/ /* * Class: com_example_jni_thread_demo_JNI_ThreadActivity * Method: setJNIEnv * Signature: ()V *//*不用JNI_OnLoad时的复杂命名方式 JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_setJNIEnv (JNIEnv *env, jobject obj) { // 保存全局JVM以便在子线程中使用 (*env)->GetJavaVM(env, &g_jvm); // 不能直接赋值(g_obj = ojb) g_obj = (*env)->NewGlobalRef(env, obj); }*/ JNIEXPORT void JNICALL native_mainThread(JNIEnv *env, /*jclass clazz*/ jobject obj)// 使用jclass和jobject都可以 { LOGI("native_mainThread"); int i; pthread_t pt[NUMTHREADS]; for(i=0; i<NUMTHREADS; i++) { // 创建线程,并指明调用的函数,注意只接收一个参数i作为thread_fun的参数,后面会介绍怎么传多个参数 pthread_create(&pt[i], NULL, &thread_fun, (void*)i); } } JNIEXPORT void JNICALL native_setJNIEnv(JNIEnv *env, /*jclass obj*/ jobject obj)// 使用jclass和jobject都可以 { LOGI("native_setJNIEnv"); // 保存全局JVM以便在子线程中使用 (*env)->GetJavaVM(env, &g_jvm); // 不能直接赋值(g_obj = ojb) g_obj = (*env)->NewGlobalRef(env, obj); } /** * Table of methods associated with a single class. */ static JNINativeMethod gMethods[] = { {"mainThread", "()V", (void*)native_mainThread }, // 绑定:注意千万签名结尾不能加分号!!!!!! {"setJNIEnv", "()V", (void*)native_setJNIEnv }, }; /* * Register several native methods for one class. */ static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } /* * Register native methods for all classes we know about. */ static int registerNatives(JNIEnv* env) { if (!registerNativeMethods(env, JNIREG_CLASS, gMethods, sizeof(gMethods) / sizeof(gMethods[0]))) return JNI_FALSE; return JNI_TRUE; } /* * Set some test stuff up. * * Returns the JNI version on success, -1 on failure. */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("GetEnv failed!"); return -1; } //=========================================== assert(env != NULL); if (!registerNatives(env)) {// 注册本地方法 return -1; } //=========================================== /* success -- return valid version number */ result = JNI_VERSION_1_4; return result; }
Android.mk文件中的代码:
LOCAL_PATH :=$(call my-dir) include $(CLEAR_VAR) LOCAL_MODULE := JNIThread LOCAL_SRC_FILES := JNI_Thread.c LOCAL_MODULE_FILENAME := libJNIThread//如果报LOCAL_MODULE_FILENAME的错的话,需要加上这句话 LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
如何给线程函数传递多个参数:
涉及多参数传递给线程的,都需要使用结构体将参数封装后,将结构体指针传给线程
定义一个结构体
struct mypara { var para1;//参数1 var para2;//参数2 }
将这个结构体指针,作为void *形参的实际参数传递
struct mypara pstru; pthread_create(&ntid, NULL, thr_fn,& (pstru));
函数中需要定义一个mypara类型的结构指针来引用这个参数
void *thr_fn(void *arg) { mypara *pstru; pstru = (* struct mypara) arg; pstru->para1;//参数1 pstru->para2;//参数2 }
如何多线程同步通信:
至于多个线程是怎么进行同步通信的,可以参考这篇博文
http://blog.csdn.net/chenghongyue/article/details/8124976