Android(在 Scala 中):StackOverflowError 取决于何时启动线程?

发布于 2024-12-11 20:55:31 字数 2657 浏览 0 评论 0原文

我有这个简单的 Activity(在 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
  }

事情就会这样美好的。

我无法解释这一点。

I have this simple Activity (in Scala, imports ommited):

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")
    })
  }
}

As you can see, mThread is started immediately, run is overridden tail-recursively, it sends an empty message to mHandler, sleep for a short period and sends the same message again. When the activity starts, I get this error:

....
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)
...

Now if I don't start mThread immediately after its creation, like this:

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

and trigger it somewhere else, say, on a touch event:

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

things will be just fine.

I can't explain this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不乱于心 2024-12-18 20:55:32

因此,我做了一些实验,我必须得出结论,如果具有尾部递归重写 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 开发。

So I did some experiments and I have to conclude that if the Thread with a tail-recursively overridden run is started off in the same expression of its creation, the tail-call optimization will fail (or is any other reason that can cause the error?)

Bad:

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

Good:

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

P.S. I'm running Scala 2.9.1, but using 2.8.2 for Android development due to the smaller library size.

箹锭⒈辈孓 2024-12-18 20:55:32

如果你想立即启动线程,为什么不把它放在onCreate()中呢?
我不确定,但我认为 thread 和 onCreate 的顺序可能会导致错误。

If you want start thread immediately, why don't you put it in onCreate()?
I'm not sure, but I think the order of thread and onCreate maybe cause error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文