本文參考了 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