Android下的JNI创建多线程的方法
本文参考了http://www.cnblogs.com/lknlfy/archive/2012/03/16/2400786.html这篇博文,加了点自己的东西
本文转自 : http://blog.csdn.net/panda1234lee/article/details/13503291
- 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