This article first appeared in the public micro-channel number "byte floating"
NDK development of this blog series:
- NDK compilation of three ways
- NDK introduction of third-party development of static and dynamic libraries
- NDK interact with Native Java development
- NDK POSIX multithreaded programming
- NDK Android OpenSL ES audio capture and playback
- NDK FFmpeg compilation
- NDK FFmpeg audio and video decoding
- NDK live streaming media server set up
- NDK push live streams and drainage
- NDK development issues quickly locate Crash
- NDK Native Development in the static registration and dynamic registration method
- Several important points NDK Development
In general steps Native Java object access layer
Java objects may be freely accessed through the JNI Native layer, Java objects are generally divided into three access steps.
-
- By
GetObjectClass
orFindClass
acquired class object reference;
- By
-
- By
GetXXMethodID
,GetXXFieldID
Methods acquired Java object access methods and properties of the ID;
- By
-
- By
CallXXMethod
,GetXXField
,SetXXField
Methods achieve access to the Java object method calls and properties.
- By
A simple example.
package com.byteflow.framework;
public interface NDKCallback {
void onProcessorCallback(int processorUId, int errorCode, Object objResult);
}
//获取到 class 对象的引用
jclass callbackClass = env->GetObjectClass(callbackObj);
//获取到 Java 对象方法的访问 ID
mOnProcessorCallbackMID = env->GetMethodID(callbackClass, "onProcessorCallback", "(IILjava/lang/Object;)V");
//调用 Java 对象的方法
env->CallVoidMethod(callbackObj, mOnProcessorCallbackMID, processorUID, errCode, objResult);
When accessing the JNI using Java objects, and the reference value is passed to note the distinction between transmission, such as basic types jint, jchar, jdouble like are passed by value, and jstring, jobject, etc. to reference.
另外,注意区分 FindClass 和 GetObjectClass 两个 JNI 方法的使用。FindClass 只需要完整的类名便可获得 class 对象的引用,而 GetObjectClass 通过 JNI 传入的一个 Java 对象的引用来获取 class 对象的引用。
在 Native 层中 Java 对象的引用类型
在 JVM 中 Java 对象的引用类型分为 “强、软、弱、虚” ,我们常用的一般是弱引用,而在 Native 层中 Java 对象的引用类型一般分为 3 种,即 LocalReference 、GlobalReference 、WeakGlobalReference 。
LocalReference 称为本地引用或局部引用,JNI 传入的 jobject 以及利用 JNI 函数创建的临时 jobject 对象一般是本地引用,其特点是一旦 JNI 调用完成,jobject 对象就会被回收掉,但可能不会被立即回收,需要注意其生命周期,强制立即回收调用 env->DeleteLocalRef(obj);
。
GlobalReference 称为全局引用,其特点是如果不主动释放,在进程生命周期里其对应的对象一直不会被回收。由此可见,全局引用若使用不当容易造成内存泄漏,全局引用的使用和释放应成对出现:
//创建
env->NewGlobalRef(g_obj);
...
//释放
env->DeleteGlobalRef(g_obj);
其使用场景是,在 JNI 调用完成后,想要继续使用 jobject 对象,需要将其设置为 GlobalReference 。
WeakGlobalReference 称为弱全局引用,其特点是在程序运行期间,该引用对应的对象随时可能会被 GC 回收(如内存不足时),需要谨慎使用。
JNIEnv 和 JavaVM 类型的作用域
JNIEnv 这个结构体比较特殊,主要提供 JNI 调用环境,JNIEnv 类型的变量是线程相关,即一个线程会对应一个 JNIEnv 变量,也就是说 JNIEnv 类型的指针不能在不同的线程中共用。
To access Java objects in a sub-thread, it is necessary to obtain the corresponding JNIEnv type variable pointer by AttachCurrentThread
, DetachCurrentThread
acquired and released.
JavaVM type of variable is related to the process, namely a Java virtual machine corresponds to a variable of type JavaVM, through env->GetJavaVM(&g_jvm);
available JavaVM pointer of the current process.
A simple example.
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public void callbackFromJNI(int errCode, Object result) {
Log.d(TAG, "callbackFromJNI() called with: errCode = [" + errCode + "], result = [" + result + "]");
}
}
//全局变量
JavaVM *g_jvm = NULL;
jobject g_obj = NULL;
void *posix_run(void* arg)
{
JNIEnv *env;
jclass cls;
jmethodID mid;
//Attach 当前线程获取 JNIEnv
if(g_jvm->AttachCurrentThread(&env, NULL) != JNI_OK)
{
return NULL;
}
//获取 class 对象
cls = env->GetObjectClass(g_obj);
//获取 MethodID
mid = env->GetMethodID(cls, "callbackFromJNI", "(ILjava/lang/Object;)V");
//调用对象方法
env->CallVoidMethod(cls, mid , 0, NULL);
//Detach 当前线程
g_jvm->DetachCurrentThread();
return NULL;
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_byteflow_ndk_MainActivity_stringFromJNI(JNIEnv* env, jobject obj) {
//获取 JavaVM
env->GetJavaVM(&g_jvm);
//创建对象的全局引用
g_obj = env->NewGlobalRef(obj);
pthread_t tid;
//创建子线程
pthread_create(&tid, NULL, &posix_run, NULL);
//阻塞主线程等待子线程结束
pthread_join(tid, NULL);
//释放对象的全局引用
env->DeleteGlobalRef(g_obj);
return NULL;
}
Contacts and exchanges
Micro-channel public number of
individual micro letter