Java – Android (in scala): stackoverflowerror depends on when to start a thread?

I have this simple activity (imported in 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")
    })
  }
}

As you can see, mthread starts immediately and the run is rewritten by tail recursion. It sends an empty message to mhandler, hibernates briefly and sends the same message again When the activity started, I received 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 creation, like this:

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

And trigger it on the touch event, for example:

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

Things will be fine

I can't explain that

Solution

So I did some experiments, and I have to conclude that if a thread running with tail recursive rewriting starts in the same expression it creates, the tail call optimization will fail (or any other reason for 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
}

Attachment: I'm running Scala 2.9 1, but because the library size is small, 2.8.0 is used 2. Android development

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>