2

我正在构建一个 Android 应用程序(使用 Scala 2.9)并且正在使用渲染到 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
  }
}

现在,使用 a 或类似工具手动实现这一点相对容易ConcurrentLinkedQueue,但我真的不想在这里重新发明轮子。此外,使用这样的演员/队列回发到 UI 也很好——现在我正在使用 Android 支持将(异步)Runnable 发布到 UI 线程。

我简要介绍了几种不同的actor实现(主要是标准的Scala和Scalaz)和一些不同的Java“消息传递”库,例如Jetlang,但大多数似乎都使用隐式线程或线程执行器服务。但是,就我而言,我希望在特定线程上的特定时间[运行参与者并]处理消息。对于 View.sendMessage,消息也应该在 UI 线程上处理,但时间并不那么重要,并且可以从上面提到的 Runnable 执行中捎带。

然后,我想我的问题是,鉴于上述情况:

在这两个线程之间提供数据的“高效”和惯用方法是什么?

(我也愿意接受我完全无法理解 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 回答