我正在为 Android 编写 native 代码,我希望在其中解压缩数据 block 。我正在从 native JNI 函数调用 Java 方法。此 Java 方法调用 BitmapFactory,然后尝试使用以下命令分配一些内存:
int[] pixels = new int[width * height];
当程序似乎崩溃或停止或发生其他情况时,给我“挂起时旋转”,然后在 VM 关闭之前 logcat 中出现大量涌出。
为了在深入了解细节之前先给出大局,我试图将压缩图像的字节数组转换为 width*height*bpp
未压缩图像以返回给 native 代码。我正在尝试使用 Android Java BitmapFactory 来进行解压缩,这似乎工作正常。压缩的字节 block 是之前加载到 native 代码中的 JPG 或 PNG 图像(并且无法从我的系统中的磁盘读取)。
顺序有点复杂,我不确定什么是相关的,所以我会全部说出来:
类 MyRenderer 实现 GLSurfaceView.Renderer
方法 onSurfaceCreated
调用 native init()
,该方法在 MyRenderer
类中定义:
static {System.loadLibrary("glprog");
}
public native void init(int dummy_variable);
在 native 代码中,这是调用的函数:
JNIEXPORT void JNICALL Java_com_pitransviewersingleimageres_MyRenderer_init(JNIEnv * env, jobject obj, jint dummy_variable) {
glprog_init(dummy_variable);
}
然后调用另一个 native 函数char glprog_init(int dummy_variable)
它本身调用 native
wrapper_uncompress_image_by_os(overlay_compressed_data,overlay_compressed_data_len,...
这是 native 函数:
char wrapper_uncompress_image_by_os(unsigned char *compressed_data, int compressed_len, //input compressed data
char *data_name_string, char *suffix, //name and type
int slot_num) {
jstring jnamestring = (*preset_env)->NewStringUTF(preset_env,data_name_string);
jstring jsuffix = (*preset_env)->NewStringUTF(preset_env,suffix);
//create byte[] and copy data in
jbyteArray retArray = (*preset_env)->NewByteArray(preset_env, compressed_len);
if(retArray==NULL) {__android_log_write(ANDROID_LOG_INFO, "NATIVE","ERROR wrapper_uncompress_image_by_os: calling NewByteArray()");return-1;}
jbyte *javaptr = (*preset_env)->GetPrimitiveArrayCritical(preset_env, (jarray)retArray, 0);
if(javaptr==NULL) {__android_log_write(ANDROID_LOG_INFO, "NATIVE","ERROR wrapper_uncompress_image_by_os: calling GetPrimitiveArrayCritical()");return-1;}
memcpy(javaptr,compressed_data,compressed_len);
(*preset_env)->ReleasePrimitiveArrayCritical(preset_env, retArray, javaptr, 0);
if((preset_javaobject!=NULL)&&(preset_method_id_convertimagefromnative!=NULL))
{
jthrowable exception;
//call java function
(*preset_env)->CallVoidMethod(preset_env, preset_javaobject,preset_method_id_convertimagefromnative,
retArray,compressed_len,
jnamestring,jsuffix,slot_num);
它在调用 native init()
的同一个 Java 类 MyRenderer
中调用方法 convertImageFromNative()
。
public void convertImageFromNative(final byte[] data, int data_len, final String data_name_string, final String suffix, final int slot_num) {
//writeFile(data,data_name_string);
Bitmap bitmapqq=bytes2bitmap(data);
}
到目前为止,这似乎有效,如果我取消注释 writeFile()
,它会将所有数据写入我的 SD 卡。我在 bytes2bitmap()
内部遇到了问题。
可以从“常规”Java 中调用 bytes2bitmap()
类,但是当从 native 调用的这个类调用时,它会在 int[] Pixels = new int 处崩溃[宽度*高度];
行。
最后这是导致崩溃的代码:
Bitmap bytes2bitmap(byte[] bytes) {
Log.d("startup", "Entered MyRenderer.bytes2bitmap()");
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inDither = true;
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap=BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
if(bitmap==null) Log.d("running", "ERROR: GLESActivity.java: BitmapFactory() returns null");
int width = bitmap.getWidth();
int height = bitmap.getHeight();
bytes=null; //not sure if I should be freeing memory here, but it seems to work
int[] pixels = new int[width * height]; //crash happens here
//crashes before doing the following
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
pixels=null;
return bitmap;
}
我还没有达到将未压缩数据正确传递回 native 代码的部分,但我认为我应该首先解决这个问题。
我可以在 native 代码中创建一个 int[]
数组来传递,问题是我不知道未压缩的图像大小。
提前致谢, 标记
最佳答案
我解决了我的问题,这是我未显示的代码中的错误。
问题出在 native 代码中的(*preset_env)->CallVoidMethod(preset_env,preset_javaobject,preset_method_id_convertimagefromnative,
调用中。变量preset_env,_javaobject,_method_id_设置不正确。我将它们设置为启动一次后可以使用 native 函数 _setupnative2java() 重新使用。我的项目中有三个类。我的错误是从我的第一个 Activity 类调用 _setupnative2java() ,而不是实际包含 java 方法的 MyRenderer 类bytes2bitmap()。在调试过程中,我将此函数的另一个副本放在同名的第一个 Activity 类中。所以它有点工作,但指针错误。奇怪的是,对 MyRenderer 的修改和 logcat 调用会工作。
我实际上确实是从 MyRenderer 类调用它的,但是是从带有 instancename.MyRenderer.setupnative2java 的启动 Activity 类调用的。但也许因为它是从另一个类调用的,所以它没有获取 MyRenderer 的指针。另外,我不确定 MyRenderer 到底是如何“初始化”的。如果您为此花费了脑力,我深表歉意。
void Java_com_pitransviewersingleimageres_MyRenderer_setupnative2java(JNIEnv* env, jobject,javaThis, jint unused_variable)
{
jthrowable exception;
jclass class_id;
preset_env=env;
preset_javaobject=javaThis;
class_id = (*env)->GetObjectClass(env, javaThis);
if(class_id!=NULL)
{
preset_method_id_convertimagefromnative = (*env)->GetMethodID(env, class_id, "convertImageFromNative", "([BILjava/lang/String;Ljava/lang/String;I)V");
}
...
关于java - Android内存管理从 native JNI调用Java类并声明数据(用于图像转换),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12428653/