Не удается получить доступ к AAssetManager в собственном коде, переданном из Java в WallpaperService

Я пытаюсь получить доступ к ресурсам в собственном коде из пользовательского WallpaperService. Собственный код компилируется и работает, но при попытке получить ссылку AAssetManager из объекта AssetManager, переданного нативной функции, всегда возвращается значение NULL.

Это как-то связано с тем, что я использую Сервис, а не Активность, что приводит к тому, что ссылка AAssetManager равна NULL? В исходном коде Java AssetManager, передаваемый в собственную функцию, является допустимым и не является нулевым.

Чтобы проверить это, я использовал их демо CubeLiveWallpaper из предоставленных примеров и нацеливание на уровень API 10. Вот соответствующий код, добавленный в класс CubeWallpaper1 для доступа к нативной функциональности:

static {
    System.loadLibrary("renderer");
}

private static native void load(AssetManager mgr);

@Override
public void onCreate() {
    super.onCreate();

    AssetManager mgr = getResources().getAssets();
    load(mgr);
}

Вот код JNI, который я использую, чтобы попытаться получить действительную ссылку AAssetManager:

#include <jni.h>
#include <android/log.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>

#define TAG "CubeWallpaper1.c"

void
Java_com_example_android_livecubes_cube1_CubeWallpaper1_load(JNIEnv *env,
                                                             jobject assetManager) {

    AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
    if (mgr == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "CubeWallpaper1.c", "error loading asset   maanger");
    } else {
        __android_log_print(ANDROID_LOG_VERBOSE, "CubeWallpaper1.c", "loaded asset  manager");
    }

}

Это было воспроизведено на нескольких устройствах, но большинство тестов проводилось на HTC Desire под управлением 2.3.7.

1 ответ

Решение

Прочитайте комментарии в asset_manager_jni.h: "Обратите внимание, что вызывающая сторона отвечает за получение и хранение ссылки на виртуальную машину на объект задания, чтобы предотвратить сборку мусора во время использования собственного объекта".

В Java вы передаете объект (mgr), который может быть освобожден сборщиком мусора после вызова собственного обратного вызова. Чтобы предотвратить это, вы можете, например, создать переменную mgr в качестве частного атрибута в вашем классе и затем передать ее через метод load, такой как этот:

private static native void load(AssetManager mgr);

private AssetManager mgr;

@Override
public void onCreate() {
  super.onCreate();

  mgr = getResources().getAssets();
  load(mgr);
}

Кроме того, я думаю, что вы должны заменить свой собственный обратный вызов C++ на:

void Java_com_example_android_livecubes_cube1_CubeWallpaper1_load
     (JNIEnv *env, jobject obj, jobject assetManager) 
Другие вопросы по тегам