You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:03:14