Android下的JNI创建多线程的方法

本文参考了http://www.cnblogs.com/lknlfy/archive/2012/03/16/2400786.html这篇博文,加了点自己的东西

本文转自 : http://blog.csdn.net/panda1234lee/article/details/13503291

java的代码:

 

[java] view plain copy
  1. package com.example.jni_thread_demo;  
  2.   
  3. import android.os.Bundle;  
  4. import android.app.Activity;  
  5. import android.util.Log;  
  6. import android.view.Menu;  
  7. import android.view.View;  
  8. import android.widget.Button;  
  9.   
  10. public class JNI_ThreadActivity extends Activity {  
  11.     private Button mButton = null;  
  12.       
  13.   
  14.     @Override  
  15.     protected void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.activity_jni__thread);  
  18.           
  19.         mButton = (Button)findViewById(R.id.button);  
  20.         mButton.setOnClickListener(new View.OnClickListener() {  
  21.               
  22.             @Override  
  23.             public void onClick(View v) {  
  24.                 // 调用JNI中的函数来启动JNI中的线程  
  25.                 mainThread();  
  26.             }  
  27.         });  
  28.           
  29.         // 初始化JNI环境  
  30.         setJNIEnv();  
  31.           
  32.     }  
  33.       
  34.     //由JNI中的线程回调类方法  
  35.     private static void fromJNI(int i)  
  36.     {  
  37.         Log.v("Java---------->"""+i);  
  38.     }  
  39.        //自己定义的线程回调成员方法  
  40.     private void From_JNI_Again (int i)  
  41.     {  
  42.         Log.v("Java_object------------>"""+i);  
  43.     }  
  44.       
  45.     // 本地方法  
  46.     private native void mainThread();  
  47.     private native void setJNIEnv();  
  48.       
  49.     static  
  50.     {  
  51.         System.loadLibrary("JNIThread");  
  52.           
  53.     }  
  54. }  

jni中的代码:

  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<unistd.h>  
  4. #include<pthread.h>  
  5. #include<string.h>  
  6. #include<assert.h>  
  7.   
  8. #include<jni.h>  
  9. #include<android/log.h>  
  10.   
  11.   
  12. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "jni_thread", __VA_ARGS__))  
  13. #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "jni_thread", __VA_ARGS__))  
  14. #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "jni_thread", __VA_ARGS__))  
  15.   
  16. // 线程数  
  17. #define NUMTHREADS 5  
  18. // 指定要注册的类  
  19.   
  20. #define JNIREG_CLASS "com/example/jni_thread_demo/JNI_ThreadActivity"  
  21. // 全局变量  
  22. JavaVM* g_jvm = NULL;  
  23. jobject g_obj = NULL;  
  24.   
  25. void* thread_fun(void* arg)  
  26. {  
  27.     JNIEnv *env;  
  28.     jclass cls;  
  29.     jmethodID mid, mid1;  
  30.   
  31.     // Attach主线程  
  32.     if((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK)  
  33.     {  
  34.         LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);  
  35.         return NULL;  
  36.     }  
  37.   
  38.     // 找到对应的类  
  39.     cls = (*env)->GetObjectClass(env, g_obj);  
  40.   
  41.     if(cls == NULL)  
  42.     {  
  43.         LOGE("FindClass() Error ......");  
  44.         goto error;  
  45.     }  
  46.     // 再获得类中的方法  
  47.     mid = (*env)->GetStaticMethodID(env, cls, "fromJNI""(I)V");  
  48.     if(mid == NULL)  
  49.     {  
  50.         LOGE("GetStaticMethodID() Error ......");  
  51.         goto error;  
  52.     }  
  53.     // 最后调用java中的静态方法  
  54.     (*env)->CallStaticVoidMethod(env, cls, mid, (int)arg);  
  55.   
  56.     //获得类中的“成员”方法  
  57.     mid1 = (*env)->GetMethodID(env, cls, "From_JNI_Again""(I)V");  
  58.     if(mid == NULL)  
  59.     {  
  60.         LOGE("GetMethodID() Error ......");  
  61.         goto error;  
  62.     }  
  63.     // 最后调用类中“成员”方法  
  64.     (*env)->CallVoidMethod(env, g_obj, mid1, (int)arg);  
  65.   
  66.     //错误处理代码  
  67.     error:  
  68.     //Detach主线程  
  69.     if((*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK)  
  70.     {  
  71.         LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);  
  72.     }  
  73.   
  74.     pthread_exit(0);  
  75. }  
  76.   
  77. /* 
  78.  * Class:     com_example_jni_thread_demo_JNI_ThreadActivity 
  79.  * Method:    mainThread 
  80.  * Signature: ()V 
  81.  */  
  82. /*不用JNI_OnLoad时的复杂命名方式 
  83. JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_mainThread 
  84.   (JNIEnv *env, jobject obj) 
  85. { 
  86.     int i; 
  87.     pthread_t pt[NUMTHREADS]; 
  88.  
  89.     for(i=0; i<NUMTHREADS; i++) 
  90.     { 
  91.         // 创建线程,并指明调用的函数 
  92.         pthread_create(&pt[i], NULL, &thread_fun, (void*)i); 
  93.     } 
  94. }*/  
  95.   
  96. /* 
  97.  * Class:     com_example_jni_thread_demo_JNI_ThreadActivity 
  98.  * Method:    setJNIEnv 
  99.  * Signature: ()V 
  100.  *//*不用JNI_OnLoad时的复杂命名方式 
  101. JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_setJNIEnv 
  102.   (JNIEnv *env, jobject obj) 
  103. { 
  104.     // 保存全局JVM以便在子线程中使用 
  105.     (*env)->GetJavaVM(env, &g_jvm); 
  106.     // 不能直接赋值(g_obj = ojb) 
  107.     g_obj = (*env)->NewGlobalRef(env, obj); 
  108. }*/  
  109.   
  110. JNIEXPORT void JNICALL native_mainThread(JNIEnv *env, /*jclass clazz*/ jobject obj)// 使用jclass和jobject都可以  
  111. {  
  112.     LOGI("native_mainThread");  
  113.     int i;  
  114.     pthread_t pt[NUMTHREADS];  
  115.   
  116.     for(i=0; i<NUMTHREADS; i++)  
  117.     {  
  118.         // 创建线程,并指明调用的函数,注意只接收一个参数i作为thread_fun的参数,后面会介绍怎么传多个参数  
  119.         pthread_create(&pt[i], NULL, &thread_fun, (void*)i);  
  120.     }  
  121. }  
  122.   
  123. JNIEXPORT void JNICALL native_setJNIEnv(JNIEnv *env, /*jclass obj*/ jobject obj)// 使用jclass和jobject都可以  
  124. {  
  125.     LOGI("native_setJNIEnv");  
  126.     // 保存全局JVM以便在子线程中使用  
  127.     (*env)->GetJavaVM(env, &g_jvm);  
  128.     // 不能直接赋值(g_obj = ojb)  
  129.     g_obj = (*env)->NewGlobalRef(env, obj);  
  130. }  
  131.   
  132. /** 
  133. * Table of methods associated with a single class. 
  134. */  
  135. static JNINativeMethod gMethods[] =  
  136. {  
  137.         {"mainThread""()V", (void*)native_mainThread },   // 绑定:注意千万签名结尾不能加分号!!!!!!  
  138.         {"setJNIEnv""()V", (void*)native_setJNIEnv },  
  139. };  
  140.   
  141. /* 
  142. * Register several native methods for one class. 
  143. */  
  144. static int registerNativeMethods(JNIEnv* env, const char* className,  
  145.     JNINativeMethod* gMethods, int numMethods)  
  146. {  
  147.     jclass clazz;  
  148.     clazz = (*env)->FindClass(env, className);  
  149.     if (clazz == NULL)  
  150.     {  
  151.         return JNI_FALSE;  
  152.     }  
  153.     if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)  
  154.     {  
  155.         return JNI_FALSE;  
  156.     }  
  157.   
  158.     return JNI_TRUE;  
  159. }  
  160.   
  161. /* 
  162. * Register native methods for all classes we know about. 
  163. */  
  164. static int registerNatives(JNIEnv* env)  
  165. {  
  166.     if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,  
  167.             sizeof(gMethods) / sizeof(gMethods[0])))  
  168.     return JNI_FALSE;  
  169.   
  170.     return JNI_TRUE;  
  171. }  
  172.   
  173. /* 
  174. * Set some test stuff up. 
  175. * 
  176. * Returns the JNI version on success, -1 on failure. 
  177. */  
  178. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)  
  179. {  
  180.     JNIEnv* env = NULL;  
  181.     jint result = -1;  
  182.   
  183.     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  184.         LOGE("GetEnv failed!");  
  185.         return -1;  
  186.     }  
  187.     //===========================================  
  188.     assert(env != NULL);  
  189.   
  190.     if (!registerNatives(env))  
  191.     {// 注册本地方法  
  192.         return -1;  
  193.     }  
  194.     //===========================================  
  195.     /* success -- return valid version number */  
  196.     result = JNI_VERSION_1_4;  
  197.   
  198.     return result;  
  199. }  

Android.mk文件中的代码:

[html] view plain copy
  1. LOCAL_PATH :=$(call my-dir)  
  2.   
  3. include $(CLEAR_VAR)  
  4.   
  5. LOCAL_MODULE :JNIThread  
  6. LOCAL_SRC_FILES :JNI_Thread.c  
  7. LOCAL_MODULE_FILENAME :libJNIThread//如果报LOCAL_MODULE_FILENAME的错的话,需要加上这句话  
  8. LOCAL_LDLIBS := -llog  
  9.   
  10. include $(BUILD_SHARED_LIBRARY)  

 

如何给线程函数传递多个参数:

涉及多参数传递给线程的,都需要使用结构体将参数封装后,将结构体指针传给线程
定义一个结构体

  1. struct mypara  
  2. {  
  3.   var para1;//参数1  
  4.   var para2;//参数2  
  5. }  

将这个结构体指针,作为void *形参的实际参数传递

  1. struct mypara pstru;  
  2. pthread_create(&ntid, NULL, thr_fn,& (pstru));  

函数中需要定义一个mypara类型的结构指针来引用这个参数

  1. void *thr_fn(void *arg)  
  2. {  
  3.   mypara *pstru;  
  4.   pstru = (* struct mypara) arg;  
  5.   pstru->para1;//参数1  
  6.   pstru->para2;//参数2   
  7. }  

如何多线程同步通信:

至于多个线程是怎么进行同步通信的,可以参考这篇博文

http://blog.csdn.net/chenghongyue/article/details/8124976

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值