Android NDK C++のインスタンスを保持する方法

Android NDK C++側のインスタンスを保持する方法

C++クラスのインスタンスを保持する手順を記載
JNI側で作成したC++クラスのポインタアドレスをJava側の変数に保存してインスタンスを保持する。

Android側からは以下の順に処理を行う。
①NativeAccess生成(インスタンス生成)
②setData()、getData等のメソッドコール
③処理終了後 destroy() コール(インスタンス破棄)※必ずコールする事

Java側のNDK連携部のコード(NativeAccess.java)
package jp.co.test.ndk;

public class NativeAccess {

	// ライブラリ名
	private static final String LOAD_LIBRARY_NAME = "native_jni";

	// NativeContext
    private long mNativeContext; // ここにC++クラスのポインタアドレスを保持

	static {
		System.loadLibrary(getLoadLibraryName());
	}

	public NativeAccess() {
		native_init();
	}

	public void destroy() {
		native_destroy();
	}

	// ライブラリロード
	private static String getLoadLibraryName() {
		return LOAD_LIBRARY_NAME;
	}

    // インスタンス生成
	private native void native_init();

	// インスタンス破棄
	private native void native_destroy();

	public native void setData(int a);

	public native int getData();

}
JNI部ヘッダー(jp_co_test_ndk_NativeAccess.h) ※コマンド生成
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jp_co_test_ndk_NativeAccess */

#ifndef _Included_jp_co_test_ndk_NativeAccess
#define _Included_jp_co_test_ndk_NativeAccess
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jp_co_test_ndk_NativeAccess
 * Method:    native_init
 * Signature: (Ljp/co/test/ndk/NativeAccess;)V
 */
JNIEXPORT void JNICALL Java_jp_co_test_ndk_NativeAccess_native_1init
  (JNIEnv *, jobject);

/*
 * Class:     jp_co_test_ndk_NativeAccess
 * Method:    native_destroy
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jp_co_test_ndk_NativeAccess_native_1destroy
  (JNIEnv *, jobject);

/*
 * Class:     jp_co_test_ndk_NativeAccess
 * Method:    setData
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_jp_co_test_ndk_NativeAccess_setData
  (JNIEnv *, jobject, jint);

/*
 * Class:     jp_co_test_ndk_NativeAccess
 * Method:    getData
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_jp_co_test_ndk_NativeAccess_getData
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
JNI部コード(jp_co_test_ndk_NativeAccess.cpp)
#include "jp_co_test_ndk_NativeAccess.h"
#include <stdio.h>
#include <string.h>
#include <stdexcept>

#include "NativeAccess.h"

#define SAFE_DELETE(p) { if (p){ delete p; } p = NULL; }

// フィールド情報
struct fields_t {
    jfieldID    context;
};
static fields_t fields;

/**
 * インスタンス取得
 */
static NativeAccess* getInstance(JNIEnv* env, jobject thiz)
{
	if (fields.context == NULL) {
		return NULL;
	}
    NativeAccess* const ptr = (NativeAccess*)env->GetLongField(thiz, fields.context);
    return ptr;
}

/**
 * インスタンス保存
 */
static void setInstance(JNIEnv* env, jobject thiz, NativeAccess* na)
{
    env->SetLongField(thiz, fields.context, (jlong)na);
}

/**
 * 初期化
 */
void JNICALL Java_jp_co_test_ndk_NativeAccess_native_1init(JNIEnv *env, jobject thiz)
{
    jclass clazz;

    // クラス検索
    clazz = env->FindClass("jp/co/test/ndk/NativeAccess"); // クラス名
    if (clazz == NULL) {
        return;
    }
    fields.context = env->GetFieldID(clazz, "mNativeContext", "J"); // "J"は long型
    if (fields.context == NULL) {
        return;
    }

    // クラス生成
    NativeAccess *na = new NativeAccess();
    setInstance(env, thiz, na);
}

/**
 * 破棄
 */
void JNICALL Java_jp_co_test_ndk_NativeAccess_native_1destroy(JNIEnv *env, jobject thiz)
{
	NativeAccess* ptr = getInstance(env, thiz);
	if (ptr == NULL) {
		return;
	}
	SAFE_DELETE(ptr);
	fields.context = NULL;
}

/**
 * データ設定
 */
void JNICALL Java_jp_co_test_ndk_NativeAccess_setData(JNIEnv *env, jobject thiz, jint num)
{
	NativeAccess* ptr = getInstance(env, thiz);
	if (ptr == NULL) {
		return;
	}
	ptr->setData(num);
}

/**
 * データ取得
 */
jint JNICALL Java_jp_co_test_ndk_NativeAccess_getData(JNIEnv *env, jobject thiz)
{
	NativeAccess* ptr = getInstance(env, thiz);
	if (ptr == NULL) {
		return 0;
	}
	return ptr->getData();
}
C++部クラスヘッダー(NativeAccess.h)
class NativeAccess
{
public:
	NativeAccess();
	~NativeAccess();
	void setData(int);
	int getData();
private:
	int _num;
};
C++部クラスコード(NativeAccess.cpp)
#include "NativeAccess.h"

#include <stdio.h>

/**
 * コンストラクタ
 */
NativeAccess::NativeAccess() {
	_num = 0;
}

/**
 * デストラクタ
 */
NativeAccess::~NativeAccess(){
}

/**
 * データ設定
 */
void NativeAccess::setData(int n) {
	_num = n;
}

/**
 * データ取得
 */
int NativeAccess::getData() {
	return _num;
}