我有一个使用谷歌native_app_glue包装器的原生Android应用程序。我想获得一个小于全屏的表面来渲染GLES。在使用从"活动"派生的java层的GLES应用程序中,这是通过java层中的getWindow((.setLayer((实现的。然而,我的项目情况不允许我使用这个解决方案。
通过nativeActivity和native_app_glue层,我可以使用JNI将Java类和回调到Java中,但不能修改View层次结构。当通过JNI从我的C代码回调setLayers((时,我得到了这个错误,因为NativeActivity与在.中创建View层次结构不在同一个线程中
E/AndroidRuntime(21503(:android.view.ViewRoot$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能访问其视图。
这是我的代码:
// Call Java to set Window size
//-----------------------------------------------------------------------------
int CallJavaWindowSize(struct android_app* state, jint width, jint height)
//-----------------------------------------------------------------------------
{
JNIEnv *env;
jclass nativeActivityClass;
jobject nativeActivityObj;
jmethodID mid;
jobject windowObj;
bool didAttachment = false;
int ret = -1;
JavaVMAttachArgs JVMAttachArgs;
jint result = state->activity->vm->GetEnv((void**) &env, JNI_VERSION_1_6);
if (!env && result == JNI_EDETACHED)
{
JVMAttachArgs.version = JNI_VERSION_1_6;
JVMAttachArgs.name = "NativeThread";
JVMAttachArgs.group = NULL;
if (state->activity->vm->AttachCurrentThread(&env, NULL) < 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to attach to thread");
return ret;
}
__android_log_print(ANDROID_LOG_DEBUG, "PowerLift", "CallJavaWindowSize() attached to Thread");
didAttachment = true;
}
else if (result < 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to GetEnv()");
return ret;
}
// retrieves NativeActivity class
nativeActivityObj = state->activity->clazz;
//nativeActivityClass = env->FindClass("android/app/NativeActivity");
nativeActivityClass = env->GetObjectClass(nativeActivityObj);
if (!nativeActivityClass)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to Find NativeActivity class");
return ret;
}
//Run getWindow().setLayout(width,height)
mid = env->GetMethodID(nativeActivityClass, "getWindow", "()Landroid/view/Window;");
if (mid == 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to get method getWindow() with signature = ()Landroid/view/Window;");
return ret;
}
windowObj = env->CallObjectMethod(nativeActivityObj, mid);
if (windowObj == 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to CallObjectMethod for mid getWindow()");
return ret;
}
jclass classWindow = env->FindClass("android/view/Window");
mid = env->GetMethodID(classWindow, "setLayout", "(II)V");
env->CallVoidMethod(windowObj, mid, width, height);
if (didAttachment)
state->activity->vm->DetachCurrentThread();
return 0;
}
你们中的一些人可能会建议使用glViewport((绘制不到全屏的图像。该解决方案在视觉上有效,但性能较差,因为EGL驱动程序仍在处理全屏表面。
我想知道这种方法是否是最好的解决方案,因为它在架构上与使用本机应用程序包装器有很大的不同:a( 抛弃本机应用程序粘合包装器,在与JVM相同的线程中运行本机代码(或至少一部分(b( 从NativeActivity派生一个Java类,该类通过setContentView((创建视图层次结构c( 在与Java在同一线程中运行的本机代码中,使用JNI调用setLayout((d( 本机代码的其余部分可以根据需要在不同的线程中运行
我不确定上述方法是否可行,也不确定我是否会因此遇到障碍。
如果要从像素缓冲区进行字符串渲染,则可能需要使用glSubTexImage2D()
。