看个关于日志的知识点
在jni中输出日志的时候:
#define TAG "JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
然后就直接可以在jni中使用LOGI来输出日志了
提出问题:
如何在jni中开启一个新线程,并且回调到我们的MainActivity中的方法
每个线程的JNIEnv的实例是相互独立的,所以我们要在jni中开启新线程就必须为该线程创建JNIEnv实例
1.每个进程有一个JavaVM
2.每个线程有一个JNIEnv
MainActivity.java
private native void setJNIEnv();
private native void newThreadInJNI();
private static void callStaticBack(int value)
{
Log.e("abc","from static----->"+value);
}
private void callBack(int value)
{
Log.e("abc","from ----->"+value);
}
1.在onCreate中调用setJNIEnv()方法
2.点击按钮调用newThreadInJNI()方法
其余两个方法是从jni新线程中回调的
native-lib.cpp
#include
#include
#include
#include
#include
#include
#define TAG "HZP_JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
// 获取数组的大小
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
JavaVM *javaVM=NULL;
jobject job=NULL;//相当于MainActivity
JNIEXPORT void JNICALL native_setJNIEnv
(JNIEnv *env, jclass clazz) {
env->GetJavaVM(&javaVM);
//保存MainActivity对象
job=env->NewGlobalRef(clazz);
}
void *start_thread(void * args)
{
JNIEnv * env;
if((javaVM->AttachCurrentThread(&env,NULL))!=JNI_OK)
{
LOGI("%s AttachCurrentThread error failed ",__FUNCTION__);
return NULL;
}
jclass jcl;
jmethodID jsmd;
jmethodID jmd;
jcl=env->GetObjectClass(job);
if(jcl==NULL)
{
LOGI("findClass error....");
goto error;
}
LOGI("call static back begin");
jsmd=env->GetStaticMethodID(jcl,"callStaticBack","(I)V");
if(jsmd==NULL)
{
LOGI("GetStaticMethodID error....");
goto error;
}
env->CallStaticVoidMethod(jcl,jsmd,(int)((size_t)args));
LOGI("call back begin");
jmd=env->GetMethodID(jcl,"callBack","(I)V");
if(jmd==NULL)
{
LOGI("GetMethodID error....");
goto error;
}
env->CallVoidMethod(job,jmd,(int)((size_t)args));
error:
if((javaVM->DetachCurrentThread())!=JNI_OK)
{
LOGI("%s DetachCurrentThread error failed ",__FUNCTION__);
}
pthread_exit(0);
}
JNIEXPORT void JNICALL native_newThreadInJNI
(JNIEnv *env, jclass clazz) {
pthread_t pt[5];
for(int i=0;i<5;i++)
{
pthread_create(&pt[i],NULL,&start_thread,(void*)i);
}
}
const JNINativeMethod gMethods[] = {
{
"setJNIEnv","()V",(void*)native_setJNIEnv
},
{
"newThreadInJNI","()V",(void*)native_newThreadInJNI
}
};
int registerNatives(JNIEnv* engv)
{
LOGI("registerNatives begin");
jclass clazz;
clazz = engv -> FindClass("com/example/huozhenpeng/myapplication/MainActivity");
if (clazz == NULL) {
LOGI("clazz is null");
return JNI_FALSE;
}
if (engv ->RegisterNatives( clazz, gMethods, NELEM(gMethods)) < 0) {
LOGI("RegisterNatives error");
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
LOGI("jni_OnLoad begin");
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGI("ERROR: GetEnv failed\n");
return -1;
}
assert(env != NULL);
registerNatives(env);
return JNI_VERSION_1_4;
}
我们用logcat看下日志:
hhh:~ huozhenpeng$ adb logcat -v threadtime -> ./log.txt
10-04 19:22:00.330 23213 23876 I HZP_JNI : call static back begin
10-04 19:22:00.330 23213 23879 I HZP_JNI : call static back begin
10-04 19:22:00.330 23213 23879 E abc : from static----->4
10-04 19:22:00.330 23213 23876 E abc : from static----->1
10-04 19:22:00.330 23213 23879 I HZP_JNI : call back begin
10-04 19:22:00.330 23213 23876 I HZP_JNI : call back begin
10-04 19:22:00.331 23213 23879 E abc : from ----->4
10-04 19:22:00.331 23213 23876 E abc : from ----->1
10-04 19:22:00.332 23213 23878 I HZP_JNI : call static back begin
10-04 19:22:00.332 23213 23878 E abc : from static----->3
10-04 19:22:00.332 23213 23878 I HZP_JNI : call back begin
10-04 19:22:00.332 23213 23877 I HZP_JNI : call static back begin
10-04 19:22:00.332 23213 23878 E abc : from ----->3
10-04 19:22:00.332 23213 23877 E abc : from static----->2
10-04 19:22:00.332 23213 23877 I HZP_JNI : call back begin
10-04 19:22:00.333 23213 23877 E abc : from ----->2
10-04 19:22:00.334 23213 23875 I HZP_JNI : call static back begin
10-04 19:22:00.335 23213 23875 E abc : from static----->0
10-04 19:22:00.335 23213 23875 I HZP_JNI : call back begin
10-04 19:22:00.335 23213 23875 E abc : from ----->0
//保存MainActivity对象
job=env->NewGlobalRef(clazz);
这块可能造成内存泄露,我们顶一个释放内存的方法:
private native void releaseGloableRefJNI();
@Override
protected void onDestroy() {
super.onDestroy();
releaseGloableRefJNI();
}
const JNINativeMethod gMethods[] = {
{
"setJNIEnv","()V",(void*)native_setJNIEnv
},
{
"newThreadInJNI","()V",(void*)native_newThreadInJNI
}
,
{
"releaseGloableRefJNI","()V",(void*)native_releaseGloableRefJNI
}
};
JNIEXPORT void JNICALL native_releaseGloableRefJNI
(JNIEnv *env, jclass clazz) {
env->DeleteGlobalRef(job);
}