1

別スレッドで Android OpenGL を処理するプログラムを書いています。しかし、このコードの場合はフリーズします。たとえば、同じスレッドの場合、task.get() を呼び出さずにメソッドを直接処理します。そのような方法は存在しますか?

public void onSurfaceCreated(GL10 arg0, EGLConfig arg1)
{
    Thread t = new Thread(new Runnable(){
        @Override
        public void run()
        {
            FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
                @Override
                public Object call() {
                    return null;
                }
            });
            gv.queueEvent(task);
            try{
                task.get();
            }catch(Exception e){

            }
            Log.i("MainActivity", "Done");    // <- Work
        }
    });
    t.start();

    FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
        @Override
        public Object call() {
            return null;
        }
    });
    gv.queueEvent(task);
    try{ task.get(); }catch(Exception e){}    // <- Freeze
    Log.i("MainActivity", "Done");
4

1 に答える 1

1

あなたの質問を正しく解釈すれば、または他の非同期ソリューションを使用せずに OpenGL スレッドで実行したいコードがいくつかあります。FutureTaskRunnable

まず、このコード (およびそのデータ) は他のスレッドに依存していますか? 他のコード/データと同期する必要がありますか? はいの場合はqueueEvent()、別のスレッドから使​​用する必要があります。OpenGL スレッド内に完全にとどまりたいので、実行されるコードは他の (非 GL) スレッドとは何の関係もないと仮定します。

FutureTask.get()さらに、コードを実行するはずのスレッドと同じスレッドから呼び出してはいけませんFutureTask。スレッドが自分自身を待っている場合、誰がジョブを実行しますか? また、別のスレッドから GL スレッドにコードを送信する場合は、使用しないでくださいFutureTask。単純なものを使用するだけRunnableです(への引数としてqueueEvent())。

主な質問に戻ります: GL スレッドから なしqueueEvent()で何かを実行するには、そのジョブを正確にどのように実行するか、つまりいつ (どこで) 正確に呼び出すかを決定する必要があります。が呼び出されるたびにonDrawFrame()呼び出されますか? onSurfaceChanged()それともonSurfaceCreated()呼ばれるたびに?

を使用したのでqueueEvent()、次回のonDrawFrame()呼び出しの前にコードを実行する必要があると思います。Android GL スレッドでは、内部的に、呼び出しの順序は次のとおりです。

  1. Android は、キューに入れられたすべてのイベントを処理します (これを少し単純化しましたが、要点は問題ありません)。
  2. 必要に応じて、Android が呼び出しますonSurfaceCreated()
  3. 必要に応じて、Android が呼び出しますonSurfaceChanged()
  4. Android 通話onDrawFrame()

つまり、簡単に言うと、追加したコードqueueEvent()は次のレンダリング サイクル ( onDrawFrame()) の前に実行されます。の GL スレッドでこのコードを実行する場合はonDrawFrame()、次のように の先頭に追加できますonDrawFrame()

@Override
public void onDrawFrame(GL10 gl) {
    if (mDoJob) {
        mDoJob = false;

        // perform code
    }

    ...
}

ここで、mDoJobvolatile変数です。true別のスレッドから設定できます。ただし、これは、シグナルを使用する他のスレッドとの追加の同期が必要ないことを前提としていることに注意してくださいmDoJob。つまり、条件ブロックで実行されるすべてのコードは、他のmDoJobものとさらに同期しなくても問題ありません。

queueEvent()基本的に、上で提示したのは、他のスレッドとの同期 (最新の変数も含む) を必要としないことを前提とした、単純化された (非同期の) 置き換えソリューションです。

シグナリング (他のスレッドとの依存関係) が必要なく、 の値がmDoJobOpenGL スレッド内 ( または 内) で決定できる場合onDrawFrame()onSurfaceCreated()onSurfaceChanged()揮発mDoJob性である必要はありません。このような場合、OpenGL スレッド内にとどまるため、非同期 (したがって同期) ソリューションは必要ありません。

具体的にまとめるとonSurfaceCreated()、コードを で実行するかどうかを決定したい場合onDrawFrame()は、 で設定した (非揮発性の) ブール変数を使用し、onSurfaceCreated()それをチェックインしonDrawFrame()ます (上記のコード例のように)。

于 2012-12-20T09:31:35.137 に答える