Android原生库JNI_OnLoad中读取Assets JSON文件遇空指针问题求解
解决JNI_OnLoad中无法获取AssetManager加载assets资源的问题
问题核心
JNI_OnLoad的执行时机早于Activity的onCreate方法(因为库在静态代码块中加载),此时Activity实例尚未初始化,无法通过Activity对象获取有效的AssetManager,直接调用会触发空指针异常,最终导致AAssetManager_fromJava返回NULL。
可行解决方案
无法在JNI_OnLoad阶段直接完成资源加载,必须将资源加载逻辑延迟到Context可用之后,通过Java层主动传递AssetManager给Native层,具体步骤如下:
- 修改Java层代码,在Activity初始化完成后主动传递
AssetManager到Native层 - Native层保存
AssetManager的全局引用,避免被GC回收 - 将原本放在JNI_OnLoad的资源加载逻辑,移到收到
AssetManager后的回调中执行
修改后的代码示例
Java层代码
public class MainActivity extends Activity { static { System.loadLibrary("nativeLibrary"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Activity初始化完成后,传递AssetManager给Native层 initNativeAssetManager(getAssets()); } // Native方法:接收AssetManager并初始化Native侧资源加载 private native void initNativeAssetManager(AssetManager assetManager); @Override protected void onDestroy() { super.onDestroy(); // 释放Native层的全局引用,避免内存泄漏 releaseNativeAssetManager(); } // Native方法:释放资源 private native void releaseNativeAssetManager(); }
Native层代码
#include <jni.h> #include <android/asset_manager_jni.h> #include <cstdlib> // 全局保存AssetManager指针和对应的Java对象引用 static AAssetManager* g_asset_manager = nullptr; static jobject g_global_asset_manager = nullptr; // 接收Java层传递的AssetManager extern "C" JNIEXPORT void JNICALL Java_com_example_MainActivity_initNativeAssetManager(JNIEnv* env, jobject thiz, jobject asset_manager) { // 先释放已有资源,避免内存泄漏 if (g_asset_manager != nullptr) { AAssetManager_destroy(g_asset_manager); g_asset_manager = nullptr; } if (g_global_asset_manager != nullptr) { env->DeleteGlobalRef(g_global_asset_manager); g_global_asset_manager = nullptr; } // 创建全局引用并转换为AAssetManager g_global_asset_manager = env->NewGlobalRef(asset_manager); g_asset_manager = AAssetManager_fromJava(env, g_global_asset_manager); // 此时AssetManager有效,执行资源加载 loadJsonFromAssets(); } // 加载assets中的JSON文件 void loadJsonFromAssets() { if (g_asset_manager == nullptr) { return; } // 打开assets目录下的目标JSON文件(替换为你的文件名) AAsset* asset = AAssetManager_open(g_asset_manager, "config.json", AASSET_MODE_BUFFER); if (asset == nullptr) { // 文件打开失败,自行处理错误 return; } // 读取文件内容 off_t file_len = AAsset_getLength(asset); char* json_buf = static_cast<char*>(malloc(file_len + 1)); if (json_buf != nullptr) { AAsset_read(asset, json_buf, file_len); json_buf[file_len] = '\0'; // 这里可以添加JSON解析逻辑,比如用cJSON等库处理 // ... free(json_buf); } // 释放资源 AAsset_close(asset); } // 释放Native层的全局引用 extern "C" JNIEXPORT void JNICALL Java_com_example_MainActivity_releaseNativeAssetManager(JNIEnv* env, jobject thiz) { if (g_asset_manager != nullptr) { AAssetManager_destroy(g_asset_manager); g_asset_manager = nullptr; } if (g_global_asset_manager != nullptr) { env->DeleteGlobalRef(g_global_asset_manager); g_global_asset_manager = nullptr; } }
关键注意事项
- 全局引用管理:必须使用
NewGlobalRef保存Java层传递的AssetManager,避免局部引用被GC回收导致Native层指针失效;同时要在Activity销毁时释放引用,防止内存泄漏。 - 错误处理:实际开发中要添加完善的错误处理逻辑,比如文件打开失败、内存分配失败等场景的容错处理。
内容的提问来源于stack exchange,提问作者Ghostop
相关产品推荐
相关产品推荐

