2

私は(Scala 2.9を使用して)Androidアプリケーションを構築しており、SurfaceViewにレンダリングするスレッドを使用しています。これはゲーム用なので、できるだけ頻繁に更新する必要があります。この問題は、入力が別のスレッドから来る他のゲームの「イベントループ」に似ていると思います。

これは、同期に依存する現在のアプローチの概算です。これは「十分に機能します」が、明示的な同期を使用し、ビュー/入力スレッドを「拘束」する必要があることについて、一般的な不安があります。

ビュー、「UIスレッド」:

def View.onTouchEvent(e) { // on UI thread
  Game.handleInput(e)
}

ゲーム、「ゲームスレッド」:

def Game.handleInput(e) = S synchronized { // on UI thread
  alterStateBasedOnInput
}
def Game.run () { // on Game thread 
  while (running) {
    S synchronized { 
      doGameStuff
    }
    View.post(someStateRelayedViaRunnable)
    yield
  }
}

明示的に同期を使用する代わりに、次のようなものが必要です。

def View.onTouchEvent(e) { // on UI thread
   Game.sendMessage(e)
}
def Game.run () { // on Game thread 
  while (running) {
    processMessage
    doGameStuff
    View.sendMessage(someState) // hopefully same as Game.sendMessage
    yield
  }
}

さて、これは、または同様のものを使用して手動で実装するのは比較的簡単ですがConcurrentLinkedQueue、ここで車輪の再発明をしたくはありません。さらに、このようなアクター/キューを使用してUIにポストバックすることもできます。現在、Androidのサポートを使用して(非同期の)RunnableをUIスレッドにポストしています。

いくつかの異なるアクター実装(主に標準のScalaとScalaz)とJetlangなどのいくつかの異なるJava「メッセージパッシング」ライブラリを簡単に見てきましたが、ほとんどは暗黙のスレッドまたはスレッドエグゼキューターサービスを使用しているようです。しかし、私の場合、特定のスレッドで特定の時間にメッセージを[アクターを実行して]処理したいと思います。View.sendMessageの場合、メッセージもUIスレッドで処理する必要がありますが、タイミングはそれほど重要ではなく、上記のRunnableの実行から便乗する可能性があります。

次に、上記のことを考えると、私の質問は次のようになります。

「効率的」で慣用的なアプローチのように、これら2つのスレッド間でデータをフィードするための良いアプローチは何でしょうか。

(私はまた、Scalaアクターおよび/またはScalazアクターおよび/または他のメッセージパッシングライブラリを完全に理解できないという提案を喜んで受け入れます; Scalazは私が想像するように機能する可能性があるようですが、私が従うのは難しいです。)

4

1 に答える 1

0

さて、私はまだ上記への一般的/再利用可能なアプローチを知りたいのですが、実用性が必要です。これは、ゲームスレッドでLooperを実行し、ゲームの「イベントループのもの」をIdleHandler内に配置することでも実行できますが、その反転は好きではありませんでした。

これが私が現在それをどのように実装したかです:

ゲーム/スレッドクラス:

var handler: Handler = _ // handler created on View thread

// Send Message to Looper that exists on View thread
// (Created implicitly for all UI threads.)
def publishEvent(event: OutputEvent) {
  handler.obtainMessage(0, event).sendToTarget
}

protected val queue = new ConcurrentLinkedQueue[InputEvent]

def queueEvent(event: InputEvent) { // on UI thread
  queue.add(event)
}

def processQueuedEvents() { // on game Thread
  @tailrec
  def processNextEvent {
    val event = queue.poll
    if (event ne null) {
      doStuffWithInputEvent(event)
      processNextEvent
    }
  }    
  processNextEvent
}

override def run() { // on game Thread
  while (running) {
    processQueuedEvents
    doOtherGameStuff ~ call_publishEvent ~ etc
  }
}

クラスを表示:

// Created on UI thread, passed to Game instance
// (The Looper will dispatch Messages to Handlers.)
val handler = new Handler {
  override def handleMessage(m: Message) {
    val event = m.obj
    doStuffWithOutputEvent(event)
  }
}

// on UI thread
override def onTouch(v: View, ev: MotionEvent): Boolean = {
   // safely queued, will be processed at the start of each game loop
   game.queueEvent(InputEvent(..))
}
于 2013-01-18T00:29:50.250 に答える