web-dev-qa-db-ja.com

再起動時にフラグメント内のGLSurfaceViewがレンダリングされない

GLSurfaceViewをセットアップし、GLSurfaceView.Rendererを使用して期待どおりにレンダリングしています。私のアプリはAndroidサポートパッケージのフラグメントを使用しています。新しいフラグメントに移動するとsurfaceDestroyedが呼び出されますが、バックスタック経由でフラグメントに戻るとGLSurfaceViewはレンダリングされません。requestRenderを呼び出しても、onDrawは呼び出されません。

サーフェイスビューでonResumeおよびonPauseを呼び出す必要があることを承知しており、ホスティングフラグメントからこれを実行していますが、問題を解決していないようです。 htisメソッドに関するすべての例はアクティビティを参照していますが、これが問題になるのでしょうか?もしそうなら、フラグメント内でGLSurfaceViewをどのように使用しますか?.

洞察は非常に高く評価され、私はコードを投稿できて嬉しいですが、それは私にとってより一般的な質問のようです、

ありがとう

59
Ian Ellis

これが、GLSurfaceViewをフラグメントでセットアップする方法です。

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

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

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

}

つまり、アクティビティで行うことと同じです。これは私のユースケースで機能するので、断片的に機能するようです。コードがどのように見えるかを知らずに、これ以上言うことは困難です。

4
Learn OpenGL ES

手遅れだと知っていますが、他の人にとっては便利かもしれません。これはすでに実装済みで、エミュレーターとデバイスの両方でうまく機能するため、これが私の答えです。フラグメントと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;
}
}
4
ravi

Glsurfaceviewでフラグメントを使用するときに理解する必要がある2つのこと。少しトリッキーになりますが、一緒にいてください。新しいフラグメントに移動すると、ondestroyviewがフラグメントでglsurfaceviewを使用して自動的に呼び出され、ビュー(oncreateviewで作成して返したglsurfaceview)を破棄します。

そのため、新しいフラグメントに移動すると、onpause、onstop、ondestroyviewが自動的に呼び出され、何もしなくて済みます。 glsurfaceviewでそのフラグメントに戻ると、oncreateview、onactivitycreated、onstart、onresumeが自動的に呼び出され、何もしなくて済みます。

あなたの質問の鍵は、Android開発者のWebサイトにある)フラグメントのライフサイクルを理解し、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 );
}

Glsurfaceviewを使用してフラグメントに戻るたびにレンダリングクラスを「最初からやり直したい」場合を除き、oncreateviewでレンダリングクラス(シェーダー)を作成する必要はありません。代わりに、Fragments onCreateでレンダリングクラスを作成します。このように設定した場合は、レンダラーを設定するだけでサーフェスが提供され、onsurfacecreated、onsurfacechanged、およびondrawframeが呼び出されるので、左から開始します。自動的に。 onsurfacecreatedで最後に使用したリソースを、描画する前にondrawframeでリロードしてください。

@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    shader = new Shader(this); 

    Log.d("Fragment", "OnCreate"); 

}

フラグメントの一時停止と再開に関しては、ほとんどの場合、フラグメントを動的に置き換えてバックスタックに追加すると、これが自動的に処理されるので、単にsurface.onpause()とsurface.onResume()を適切な場所に配置するだけです。そして、あなたは行ってもいいです。

物事を明確にするために、フラグメントのライフサイクルとglsurfaceviewレンダラーを中心に展開するメソッドにログステートメントを挿入すると、何が起こっているか、何が起こっていないかを確認できます。

3
SavageKing

私はフラグメントを操作しませんが、glsurfaceが破壊された場合、おそらくOpenGLRendererのインスタンスを再度作成してglsurfaceに再アサートする必要があります。このコードは、向きを変更してすべての画面を再作成するときにアクティビティで機能します。この場合は、 glsurfaceviewをリセットするために、レイアウトのcontentviewを再度設定します。

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(); 
1
Zeus Monolitics

私はOpenGLESの専門家ではありませんが、フラグメントとそのライフサイクルを十分に切り抜けてきました。私が提案することは、フラグメントにonCreateViewを設定し、レンダラーに再度描画を開始するように伝え、それが機能しない場合は、フラグメントのonResumeから実行してみてください。フラグメントのGLサーフェスの描画に関しては、アクティビティレベルから何もする必要はありません。

1
Shaun