Fragment 中的 GlSurfaceView 在恢复时冻结 UI

问题描述 投票:0回答:1

我有一个带有

GlSurfaceView
的片段,其中有一个按钮可以将您导航到第二个片段。第二个片段还有一个
GlSurfaceView
和一个可让您导航回第一个片段的按钮。

两者

GlSurfaceView
都使用相同类型的渲染器。这是一个简单的渲染器,仅更改背景颜色。

我的问题是,如果我在第二个片段上切换到另一个应用程序然后再切换回来,整个 UI 将冻结。尽管与第二个片段相比几乎相同,但第一个片段上没有发生这种情况。

为什么会发生这种情况?我该怎么办?我的猜测是这是 Android 中的一个错误。在 Android 11 之前的旧版本中似乎运行良好。

我的渲染器在每一帧上清除帧 500 000 次。如果我只清除该帧一次,则不会出现该错误。另外,如果我导航到没有动画的第二帧,它似乎也工作正常。

我这里有一个完整的示例项目:https://github.com/pekspro/GLSurfaceViewFreezeSample

这是渲染器的代码:

public final class OpenGLRenderer implements Renderer
{
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
    }

    public void onSurfaceChanged(GL10 gl, int w, int h) {
        gl.glViewport(0, 0, w, h);
    }

    float color = 0.2f;

    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        color += 0.01f;

        if (color > 0.7) {
            color = 0.02f;
        }

        for(int i = 0; i < 500000; i++) {
            gl.glClearColor(color * 0.8f, 0.0f, color, 1.0f);
        }
    }
}

这是第一个片段的代码:

public class FirstFragment extends Fragment {

    private FragmentFirstBinding binding;

    @Override
    public View onCreateView(
            LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {
        binding = FragmentFirstBinding.inflate(inflater, container, false);

        return binding.getRoot();
    }

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        binding.OpenGlGameGraphics.setRenderer(new OpenGLRenderer());

        binding.buttonFirstWithAnimation.setOnClickListener(view1 -> {
            FragmentManager manager = getParentFragmentManager();

            FragmentTransaction ft = manager.beginTransaction();
            ft. Replace(R.id.FragmentMain, new SecondFragment());
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            ft.addToBackStack(null);

            ft. Commit();
        });

        binding.buttonFirstNoAnimation.setOnClickListener(view1 -> {
            FragmentManager manager = getParentFragmentManager();

            FragmentTransaction ft = manager.beginTransaction();
            ft. Replace(R.id.FragmentMain, new SecondFragment());
            ft.addToBackStack(null);

            ft. Commit();
        });
    }

    @Override
    public void onResume()
    {
        super.onResume();

        binding.OpenGlGameGraphics.onResume();
    }

    @Override
    public void onPause()
    {
        super.onPause();

        binding.OpenGlGameGraphics.onPause();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

这是第二个片段的代码:

public class SecondFragment extends Fragment {

    private FragmentSecondBinding binding;

    @Override
    public View onCreateView(
            LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {

        binding = FragmentSecondBinding.inflate(inflater, container, false);

        return binding.getRoot();

    }

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        binding.OpenGlGameGraphics.setRenderer(new OpenGLRenderer());

        binding.buttonSecond.setOnClickListener(view1 -> {
            FragmentManager manager = getParentFragmentManager();
            manager.popBackStack();
        });
    }

    @Override
    public void onResume()
    {
        super.onResume();

        binding.OpenGlGameGraphics.onResume();
    }

    @Override
    public void onPause()
    {
        super.onPause();

        binding.OpenGlGameGraphics.onPause();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}
android android-fragments glsurfaceview
1个回答
0
投票

似乎有效的一件事是在 GlSurfaceView 暂停时删除,然后延迟一段时间,将其添加到简历中:

@Override
public void onResume() 
{
    super.onResume();

    if (binding.OpenGlContainer.getChildCount() == 0) {
        new Handler().postDelayed(() -> {
            binding.OpenGlContainer.addView(binding.OpenGlGameGraphics);
        }, 0);
    }

    binding.OpenGlGameGraphics.onResume();
}

@Override
public void onPause() {
    super.onPause();

    binding.OpenGlGameGraphics.onPause();
    binding.OpenGlContainer.removeView(binding.OpenGlGameGraphics);
}

为什么需要这个我不明白。但似乎有效。

© www.soinside.com 2019 - 2024. All rights reserved.