I’m a big fan of the newnative activityfunctionality available for Android NDK users.

While it does limit your target audience to Android 2.3 and above (currentlycomprising less than 10%of the Android smartphone market, albeit covering 100% of the Android tablet market), it can represent a significant efficiency improvement for heavy users of the native development kit, removing most expensive JNI boundary crossings. Native activities empower and speed up native event processing.

I liberally use the NDK, and as it has been iteratively empowered by the Android developers I’ve found my motivation to build Android projects growing.

Despite years primarily dealing with higher languages and managed runtimes, I really love C++ and unmanaged code. Maybe it’s some early professional life trauma that has given me a C++ Stockholm syndrome.

The NDK importantly allows me to effectively share code across platforms, which is especially important given the state of the Android emulator: Aside from notoriously poor performance, the emulator is missing large swaths of functionality, including significant Open GL ES 2.0 functionality, ruling out its use for many graphically advanced applications.

So instead I build an application where most of the code is shared between an Android application NDK library, and a Win32 application. Conceivably an iOS port would not be that far removed, which was an important consideration.

On the Win32 front you just need to add anOpenGL ES 2.0 emulatorto intercept and rewrite graphics calls and you have a world where you can build out most of your core functionality in Visual Studio, appropriately stubbing out platform specific code like mouse/touchscreen inputs, only occasionally building in the Android NDK and running it on an actual Android device just to make sure everything still works.

It is a solution that has worked wonders for my enjoyment of non-trivial Android development.

However the NDK remains incomplete. While each iteration has seen a much richer, more self-sustaining NDK, there are certain tasks that are better done, if not only possible from, Java in the Dalvik VM.

So you need to make a JNI call from the Native Activity to Java code, whether to the system class library, or to your own custom code.

The former is easy: From the ANativeActivity instance (the definition can be found in native_activity.h), which if you use the native app glue can be found in the activity member of theandroid_appstructure you’re passed, use thevmmember to obtain a thread-attachedJNIEnvinstance.

JNIEnv *jni;

state->activity->vm->AttachCurrentThread(&jni, NULL);

Attaching the thread is necessary given that — again if you use the native glue — your code is running in a separate thread.

Now that you have the JNIEnv you can use the normalFindClassfunctionality to get system classes, and normal JNI functionality to instantiate and call Java functionality.

Things get a little dicier when you want to use the class loader to loadyour ownclasses, however, which will often be the case given that normally you’ll want to limit to jumps between the NDK and the SDK, with entrypoints that do sets of functionality and then return finalized results after lots of chatter between Java objects. It would be a serious pain to do all of that from the NDK.

FindClass off of the JNIEnv will not give satisfaction. It won’t find your classes. The reasons are because the context of the JNIEnv FindClass has no awareness that your classes exist.

This seriously vexed me last night. It is one of those frustrating problems that I’m sure have a simple answer, but many searches offered no clues. I found one guy who had the same problem, apparently finding a solution, however they left the question open with an obtuse “found my solution” claim.

I believe that people in such situations often are so irritated by the lack of assistance that they decide to do the same in return to the collective. Alternately if the answer isn’t easily found, I think some are motivated by the perception that it’s a competitive advantage for it to remain so.

In the end it turned out to be painfully obvious. You need to call thegetClassLoadermethod of theandroid.app.NativeActivityinstance that you were given in theclazzmember of theactivitymember previously discussed. This will give you a class loader that has contextual awareness of your own custom code.

In pseudo-code-

JNIEnv *jni;

state->vm->AttachCurrentThread(&jni, NULL);

jclass activityClass = jni->FindClass("android/app/NativeActivity");

jmethodID getClassLoader = jni->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");

jobject cls = jni->CallObjectMethod(state->activity->clazz, getClassLoader);

jclass classLoader = jni->FindClass("java/lang/ClassLoader");

jmethodID findClass = jni->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");

jstring strClassName = jni->NewStringUTF("com/tewdew/ClassIWant");

jclass classIWant = (jclass)jni->CallObjectMethod(cls, findClass, strClassName);

Add in error handling, free the string and detach the thread, and you have a class loader that empowers your NDK code.

tl;dr; — you need to get the class loader from your native activity. The default class loader you get otherwise is effectively just a system class loader.

I hope this proves helpful for future searchers.

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. Android(安卓)双开沙箱 VirtualApp 源码
  2. Android(安卓)APP转成launcher
  3. Android(安卓)异步加载解决方案(循环,多任
  4. Android(安卓)传输数据时Base64编码算法
  5. Android标题栏沉浸效果
  6. Android(安卓)SQLite数据库 《第一行代码
  7. Android(安卓)控件七 ImageView 控件
  8. Android(安卓)Sensor
  9. android stadio多渠道打包(一分钟搞定)
  10. Android系统服务-WindowManager