0

我有一个从本机 c 代码调用的 Java 方法。它的工作很简单,复制一个位图。但这使它毫无错误地轰炸出去。

public synchronized Bitmap copyScreen() {
    try {
        Log.d(TAG, "before copy Screen");
                          //Any of these lines make it bomb out.
        // Bitmap copy = bmp.copy(bmp.getConfig(), false);
        //Bitmap copy = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(),
        //      bmp.getConfig());
        Bitmap copy = Bitmap.createBitmap(800, 480, Config.ARGB_8888);
        Log.d(TAG, "after copy Screen");
        return copy;
    } catch (Exception ex) {
        Log.e(TAG, "copyScreen", ex);
        return null;
    }
}

我可以copyScreen毫无问题地从 Java 调用它。只有当它被 JNI 调用时,它才会爆炸。

如果我不做任何一个复制行,它也可以正常工作。

日志猫只显示:

11-15 20:10:49.234: D/GraphicsBuffer(24341): 复制屏幕前

请注意,本机代码在与主线程分开的线程中运行。我已经同步了对该字段的所有访问bmp。但即使制作一个新的位图而不会导致它退出。如果位图很小,没关系。

Bitmap copy = Bitmap.createBitmap(80, 48, Config.ARGB_8888);

有效,那么我可以从 JNI 分配的内容有一些限制吗?

4

1 回答 1

0

很确定我的问题是我保留对 java 环境的引用的方式:

我的旧 main 和 getJNIEnv

 JNIEnv *_env;

 JNIEXPORT void JNICALL Java_com_comp_prod_main(JNIEnv *env,
        jclass thiz) {
    LOGV("Main called %d", __LINE__);
    _env = (JNIEnv *) ((*env)->NewGlobalRef(env, env));
      main(); //somewhere in here it calls back to the java which creates the bitmap
    _env = NULL;
  }

  JNIEnv *getJNIEnv(void) {
     return _env;
  }

我的新 main 和 getJNIEnv

JavaVM *jvm;

JNIEXPORT void JNICALL Java_com_comp_prod_main(JNIEnv *env,
        jclass thiz) {
    LOGV("Main called %d", __LINE__);
    //this is how to cache it for other threads
    jint rs = (*env)->GetJavaVM(env, &jvm);
    assert (rs == JNI_OK);
    main(); //somewhere in here it calls back to the java which creates the bitmap
    jvm = NULL;
}

JNIEnv *getJNIEnv(void) {
    JNIEnv *env;
     jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
     assert (rs == JNI_OK);
     if(env == NULL)
     {
       LOGV("env is NULL");
     }
     return env;
}

仅供参考,所有 c 都是单线程的,但在单独的线程中运行到主线程。这是从 Java 开始的方式:

Runnable runTerm = new Runnable() {

public void run() {
  // call main()
  Log.i(TAG, "About to call main on the c!");
  try {
    Terminal.main();
    } catch (IOException e) {
     e.printStackTrace();
    }
    }
};

t = new Thread(runTerm, "C thread");
t.start();
于 2012-11-16T22:36:26.827 回答