Android (в Scala): StackOverflowError зависит от того, когда начинать поток? - PullRequest
4 голосов
/ 25 октября 2011

У меня есть это простое действие (в Scala импорт импортируется):

class TestActivity extends Activity {
  private val TAG = "TestActivity"

  private val mHandler = new Handler {
    override def handleMessage(msg: Message) {
      Log.d(TAG, "handleMessage")
    }
  }

  private val mThread = new Thread {
    override def run {
      mHandler.sendEmptyMessage(0)
      Thread.sleep(10)
      run
    }
  }.start

  override def onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(new TextView(this) {
      setText("hello, world")
    })
  }
}

Как видите, mThread запускается немедленно, run переопределяется хвостом рекурсивно, отправляет пустойсообщение на mHandler, короткое время спит и снова отправляет то же сообщение.Когда начинается действие, я получаю эту ошибку:

....
D/TestActivity(28224): handleMessage
D/TestActivity(28224): handleMessage
D/TestActivity(28224): handleMessage
D/TestActivity(28224): handleMessage
I/dalvikvm(28224): threadid=9: stack overflow on call to Landroid/os/MessageQueue;.nativeWake:VI
I/dalvikvm(28224):   method requires 8+20+0=28 bytes, fp is 0x43e33310 (16 left)
I/dalvikvm(28224):   expanding stack end (0x43e33300 to 0x43e33000)
I/dalvikvm(28224): Shrank stack (to 0x43e33300, curFrame is 0x43e35fe0)
W/dalvikvm(28224): threadid=9: thread exiting with uncaught exception (group=0x40015560)

E/AndroidRuntime(28224): FATAL EXCEPTION: Thread-10
E/AndroidRuntime(28224): java.lang.StackOverflowError
E/AndroidRuntime(28224):  at android.os.MessageQueue.enqueueMessage(MessageQueue.java:223)
E/AndroidRuntime(28224):  at android.os.Handler.sendMessageAtTime(Handler.java:457)
E/AndroidRuntime(28224):  at android.os.Handler.sendMessageDelayed(Handler.java:430)
E/AndroidRuntime(28224):  at android.os.Handler.sendEmptyMessageDelayed(Handler.java:394)
E/AndroidRuntime(28224):  at android.os.Handler.sendEmptyMessage(Handler.java:379)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:20)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22)
...

Теперь, если я не запускаю mThread сразу после ее создания, как это:

  private val mThread = new Thread {
    override def run {
      mHandler.sendEmptyMessage(0)
      Thread.sleep(10)
      run
    }
  }

и где-то ее запускаюеще, скажем, на сенсорном событии:

  override def onTouchEvent(event: MotionEvent): Boolean = {
    if (event.getAction == MotionEvent.ACTION_DOWN)
      mThread.start
    true
  }

все будет хорошо.

Я не могу этого объяснить.

Ответы [ 2 ]

1 голос
/ 26 октября 2011

Итак, я провел несколько экспериментов и должен заключить, что если поток с хвостовой рекурсивной переопределенной run запускается в том же выражении своего создания, оптимизация хвостового вызова завершится неудачно (или по любой другой причинечто может вызвать ошибку?)

Плохо:

class Test {
  val mThread = new Thread {
    override def run {
      println("hello")
      run
    }
  }.start
}

Хорошо:

class Test {
  val mThread = new Thread {
    override def run {
      println("hello")
      run
    }
  }
  mThread.start
}

PS Я использую Scala 2.9.1, но использую 2.8.2для разработки под Android из-за меньшего размера библиотеки.

0 голосов
/ 25 октября 2011

Если вы хотите немедленно запустить поток, почему бы вам не включить его в onCreate ()?Я не уверен, но я думаю, что порядок потока и onCreate может вызвать ошибку.

...