JVM提供Java运行环境 (context.....)
JNIEnv提供Java与本地代码交互框架(JNIEnv是通过JVM创建的)
通过保存JVM,我们可以把新创建的本地游戏线程attach到JVM里面运行,
然后通过JNIEnv我们可以注册本地方法到JVM里面,也可以去查询Java里面的代码来实现真正的本地代码与Java代码交互
示例代码:
MainActivity.java
package com.example.jnistudy;
import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private Button mButton = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
runOnUiThread(new Runnable(){
@Override
public void run()
{
int i = 0;
i++;
System.out.println("UIThread i = " + i);
}
});
Thread thread = new Thread(new Runnable(){
@Override
public void run()
{
int i = 0;
i++;
System.out.println("thread i = " + i);
}
});
thread.start();
mButton = (Button)this.findViewById(R.id.button);
//按钮监听
mButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
//调用JNI中的函数来启动JNI中的线程
mainThread();
}
});
//初始化JNI环境
setJNIEnv();
}
//由JNI中的线程回调
private static void fromJNI(int i)
{
System.out.println("Java------>" + i);
}
//本地方法
private native void mainThread();
private native void setJNIEnv();
static
{
//加载动态库
System.loadLibrary("JNIThreads");
}
}
JNI_Thread.cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<jni.h>
#include<android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))
//线程数
#define NUMTHREADS 5
//全局变量
JavaVM *g_jvm = NULL;
jobject g_obj = NULL;
void *thread_fun(void* arg)
{
JNIEnv *env;
jclass cls;
jmethodID mid;
//Attach主线程
if(g_jvm->AttachCurrentThread(&env, NULL) != JNI_OK)
{
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
return NULL;
}
//找到对应的类
cls = env->GetObjectClass(g_obj);
if(cls == NULL)
{
LOGE("FindClass() Error.....");
goto error;
}
//再获得类中的方法
mid = env->GetStaticMethodID(cls, "fromJNI", "(I)V");
if (mid == NULL)
{
LOGE("GetMethodID() Error.....");
goto error;
}
//最后调用java中的静态方法
env->CallStaticVoidMethod(cls, mid ,(int)arg);
error:
//Detach主线程
if(g_jvm->DetachCurrentThread() != JNI_OK)
{
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
}
pthread_exit(0);
}
extern "C" {
//由java调用以创建子线程
JNIEXPORT void Java_com_example_jnistudy_MainActivity_mainThread( JNIEnv* env, jobject obj)
{
int i;
pthread_t pt[NUMTHREADS];
__android_log_print(ANDROID_LOG_DEBUG, "JNIStudy", "Java_com_example_jnistudy_MainActivity_mainThread called");
for (i = 0; i < NUMTHREADS; i++)
//创建子线程
pthread_create(&pt[i], NULL, &thread_fun, (void *)i);
}
}
extern "C" {
//由java调用来建立JNI环境
JNIEXPORT void Java_com_example_jnistudy_MainActivity_setJNIEnv( JNIEnv* env, jobject obj)
{
//保存全局JVM以便在子线程中使用
env->GetJavaVM(&g_jvm);
//不能直接赋值(g_obj = obj)
//get the reference of main class
g_obj = env->NewGlobalRef(obj);
}
}
//当动态库被加载时这个函数被系统调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv* env = NULL;
jint result = -1;
//获取JNI版本
if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
{
LOGE("GetEnv failed!");
return result;
}
return JNI_VERSION_1_4;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JNIThreads
LOCAL_SRC_FILES := JNI_Thread.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
运行结果:
Java_com_example_jnistudy_MainActivity_mainThread called
Java------>1
Java------>0
Java------>2
Java------>4
Java------>3