【问题标题】:GLSurfaceView inside fragment not rendering when restarted重新启动时片段内部的 GLSurfaceView 不呈现
【发布时间】:2012-05-24 15:11:38
【问题描述】:

我有一个GLSurfaceView 设置并使用GLSurfaceView.Renderer 按预期呈现。我的应用程序使用来自 android 支持包的片段。当我导航到一个新片段时,surfaceDestroyed 被调用,但是当我通过后台堆栈返回片段时,GLSurfaceView 不会呈现,对 requestRender 的调用不会导致 onDraw 调用。

我知道我需要在表面视图上调用onResumeonPause,并且我正在从托管片段执行此操作,但它似乎无法解决问题。所有关于 htis 方法的例子都参考了活动,这可能是问题吗?如果是这样,您如何在片段中使用GLSurfaceView

非常感谢任何见解,我很乐意发布代码,但这对我来说似乎更像是一个普遍的问题,

谢谢

【问题讨论】:

  • 这是一个很好的问题,我也在寻找答案(如果我能找到解决方案会更新)。
  • 我没有尝试在片段中使用 GLSurfaceView,但根据我对 Internet 上基于活动的示例的经验,它们大多不完整或已过时。我认为主要问题是您需要在 onPause 中使用所有 OpenGL 资源(纹理、着色器、VBO IIRC)并在 onResume 中重新创建它们。我最近会检查我的旧代码。您是否尝试将您的确切代码放入活动中?
  • @Blackhex 代码在活动中运行良好,当我决定将其移动到片段中时,我遇到了问题。我对 OpenGL 没有太多经验,所以如果你能指出我在暂停时释放所有资源的正确方向,我会试一试。
  • 对于 onResume() 中的每个 glCreateShader()、glCreateProgram()、glGetTextures()、glGenBuffers() 和 glGenFramebuffers(),都应该有 glDeleteShader()、glDeleteProgram()、glDeleteTextures()、glDeleteBuffers()和 onPause() 中的 glDeleteFramebuffers()。我看到我在 onPause() 中也有 glBindFramebuffer(GL_FRAMEBUFFER, 0)。另一个区别是我使用的是原生 C OpenGL ES 库,而(据我所知)你使用的是 Java 绑定。

标签: android opengl-es android-fragments glsurfaceview


【解决方案1】:

这是我在片段中设置 GLSurfaceView 的方式:

onCreateView() {
    glSurfaceView = new GLSurfaceView(getActivity());
   ...
}

onPause() {
    if (glSurfaceView != null) { glSurfaceView.onPause(); }
    ...
}

onResume() {
    if (glSurfaceView != null) { glSurfaceView.onResume(); }
    ...
}

}

因此,类似于您在活动中所做的事情。这适用于我的用例,所以看起来它们确实在片段中工作。如果不知道您的代码是什么样子,很难说更多。

【讨论】:

    【解决方案2】:

    我知道为时已晚,但它可能对其他人有用 这是我的答案,因为我已经实现了它,它在模拟器和设备中都运行良好。我使用了 Fragment 和 supportV4。希望你会喜欢它。

    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import com.example.opengles20.glsurfaceview.GlSurfaceViewClass;
    import com.example.opengles20.renderer.RendererClass;
    
    public class MYGlclass extends Fragment {
    private GlSurfaceViewClass mGLView;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (container == null) {
            return null;
        }
        View view=inflater.inflate(R.layout.main, container, false);
        mGLView=(GlSurfaceViewClasss)view.findViewById(R.id.gl_surface_view);
        mGLView.setEGLContextClientVersion(2);
        RendererClass rendererclass=new RendererClass(getActivity());
        mGLView.setRenderer(rendererclass);
        mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
        return view;
    }
    }
    

    【讨论】:

      【解决方案3】:

      在使用带有 glsurfaceview 的片段时需要注意的几件事。这有点棘手,但请留在我身边。当您导航到一个新片段时,ondestroyview 会自动使用 glsurfaceview 在您的片段上调用,这会破坏您的视图(您在 oncreateview 中创建并返回的 glsurfaceview)。

      因此,当您导航到新片段时,会自动调用 onpause、onstop、ondestroyview,而无需您进行任何工作。当您使用 glsurfaceview 回到该片段时,会自动调用 oncreateview、onactivitycreated、onstart 和 onresume,无需您进行任何工作。

      您问题的关键是了解可以在 android 开发者网站上找到的片段生命周期,以及了解 glsurfaceview 的功能。

      现在,您必须使用 glsurfaceview 来实现渲染器,使用 onsurfacecreated、onsurfacechanged 和 ondrawframe。导航到另一个片段,然后使用 glsurfaceview 返回到您的片段将导致再次调用 onsurfacecreated,因为您的 glsurfaceview 在 ondestroyview 中被破坏,您的上下文已经丢失,您需要重新加载 gl 线程上的所有资源。

      最后,从您的问题来看,ondrawframe 没有被调用,这可能是由于您没有重新创建视图、设置渲染器并从 oncreateview 返回视图。

      所以在 oncreateview 你需要这样的东西

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle     
      savedInstanceState) 
      {
          View mView = inflater.inflate(R.layout.fragment_layout,  null);
      
          surface = (GLSurfaceView) mView.findViewById (R.id.glsurfaceview); 
          surface.setEGLContextClientVersion(2); 
      
          //return your view here
          return mView; 
      }
      
      
      @Override
      public void onActivityCreated(Bundle mState) 
      {
          super.onActivityCreated(mState);
      
          //setting your renderer here causes onSurfaceCreated to be called
          //if you set your renderer here then you have a context to load resources
          surface.setRenderer( shader );
      }
      

      您不想在 oncreateview 中创建渲染类(着色器),除非您希望每次使用 glsurfaceview 回到片段时都“重新开始”渲染类。相反,在您的 Fragments onCreate 中创建您的渲染类,这样,如果您设置了一些东西,那么您将从您离开的地方开始,因为只需设置渲染器将为您提供表面,这将导致 onsurfacecreated、onsurfacechanged 和 ondrawframe 被调用自动地。在绘制它们之前,请确保在 ondrawframe 中重新加载上次在 onsurfacecreated 中使用的任何资源。

      @Override
      public void onCreate(Bundle savedInstanceState) 
      {
          super.onCreate(savedInstanceState);
      
          shader = new Shader(this); 
      
          Log.d("Fragment", "OnCreate"); 
      
      }
      

      当涉及到暂停和恢复片段时,在大多数情况下,当您动态替换片段并将其添加到后台堆栈时,会自动处理,因此只需将 surface.onpause() 和 surface.onResume() 放入正确的地点,你很高兴。

      为了让事情一目了然,尝试将日志语句放在围绕片段生命周期和 glsurfaceview 渲染器旋转的方法中,您将能够看到发生了什么和没有发生什么。

      【讨论】:

        【解决方案4】:

        我不使用片段,但如果 glsurface 被破坏,可能需要再次创建 OpenGLRenderer 的实例并重新评估 glsurface,此代码在更改方向并重新创建所有屏幕的活动中对我有用,在这种情况下我必须再次设置布局的内容视图以重置 glsurfaceview:

        view.onPause(); 
        setContentView(R.layout.slidegl);
        view = (GLSurfaceView) this.findViewById(R.id.glSurface);
        renderer = new OpenGLRenderer();
        view.setRenderer(renderer); 
        view.onResume();
        

        如果您不想重新启动并设置视图的所有内容,请尝试创建 GLSurface 的新对象:

        this.view = new GLSurfaceView(); 
        

        【讨论】:

          【解决方案5】:

          我不是OpenGLES 的专家,但我已经在片段及其生命周期方面进行了足够的努力。我建议您为您的片段设置onCreateView,告诉渲染器再次开始绘制,如果这不起作用,请尝试从片段中的onResume 执行此操作。在片段中绘制GL 表面时,应该不需要从活动级别做任何事情。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-09-18
            • 1970-01-01
            相关资源
            最近更新 更多