我有一个带有
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;
}
}
似乎有效的一件事是在 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);
}
为什么需要这个我不明白。但似乎有效。